chore: clean up root directory — archive completed docs, add marketing assets

Move 9 completed/historical docs from root to docs/archive/:
- ARCHITECTURE.md, BACKLOG.md, CLAUDE-SETUP.md, MICHAEL-NOTES.md
- IMPLEMENTATION-SUMMARY-ISSUE-34.md, PHASE-2.5-PERSONAL-BRANCHING.md
- REBRAND-IMPLEMENTATION-GUIDE.md, TS-EXAMPLES.md, WORKSPACE-REMOVAL-PLAN.md

Move QUICK-START.md to docs/

Add previously untracked files:
- DEV-ENV.md (devserver01 setup guide)
- docs/marketing/ (one-pager HTML + PDF)
- docs/ResolutionFlow_Pivot_Architecture.docx

Update CLAUDE.md rebrand guide reference path.

Deleted temp files: .temp_fixed.py, .temp_fixed2.py, ai_provider_*.py,
ai_provider.patch, test_write.txt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-21 15:12:07 +00:00
parent 0c51198556
commit a955888acf
17 changed files with 1231 additions and 1 deletions

View File

@@ -0,0 +1,405 @@
# Patherly - Architecture & Overview
> **Purpose:** Core technical reference combining project vision and technical implementation.
> **Last Updated:** February 2, 2026
---
## Table of Contents
1. [Project Vision](#project-vision)
2. [Problem Statement](#problem-statement)
3. [Solution Overview](#solution-overview)
4. [Tech Stack](#tech-stack)
5. [System Architecture](#system-architecture)
6. [Database Schema](#database-schema)
7. [API Endpoints](#api-endpoints)
8. [Data Structures](#data-structures)
9. [Security](#security)
10. [Deployment](#deployment)
---
## Project Vision
A decision tree troubleshooting application designed for MSP engineers to transform diagnostic processes into clean, professional documentation automatically.
**Tagline:** "Take the path MOST traveled"
### Success Criteria
**3-Month Goal:** Michael uses this tool for 50% of his tickets
**Key Metrics:**
- Time saved per ticket
- Documentation quality improvement
- Reduction in "what did I do?" moments
- Team adoption rate
### Target Users
**Primary:** Senior Systems Engineers at MSPs managing Windows Server, Active Directory, Citrix, networking equipment
**Secondary:**
- Junior engineers needing guided troubleshooting
- Onsite technicians following remote engineer instructions
- MSP teams wanting standardized procedures
### Key Differentiators
1. **Automatic documentation generation** - No separate note-taking step
2. **On-the-fly customization** - Add custom branches when encountering edge cases
3. **Learning system** - Tracks common paths, suggests optimizations
4. **Automation integration** - Execute PowerShell/scripts directly from decision nodes
5. **Knowledge hub** - Links to documentation, KB articles, tutorials at each step
---
## Problem Statement
MSP engineers face constant context switching between diverse technical issues (file shares, server outages, VPN failures, Active Directory problems). Each context switch:
- Takes 15-25 minutes to regain full focus
- Creates cognitive overhead and attention residue
- Contributes to burnout (research-backed)
- Makes consistent documentation challenging
- Results in lost tribal knowledge
---
## Solution Overview
An intelligent decision tree system that:
- Guides engineers through proven troubleshooting paths
- Captures decisions and notes automatically
- Generates professional ticket documentation
- Builds institutional knowledge
- Reduces cognitive load during high-stress situations
---
## Tech Stack
### Frontend
| Component | Technology |
|-----------|------------|
| Framework | React 18 + Vite + TypeScript |
| Styling | Tailwind CSS |
| State Management | Zustand (with immer + zundo) |
| Routing | React Router v6 |
| API Client | Axios |
| Offline | Service Workers + IndexedDB (planned) |
### Backend
| Component | Technology |
|-----------|------------|
| Framework | Python FastAPI |
| ORM | SQLAlchemy 2.0 (async) |
| Validation | Pydantic |
| Auth | JWT (python-jose) + bcrypt |
| Migrations | Alembic |
### Database & Storage
| Component | Technology |
|-----------|------------|
| Database | PostgreSQL 16 |
| File Storage | S3-compatible (planned) |
| Development | Docker containers |
### Hosting
| Environment | Platform |
|-------------|----------|
| Development | Local (Vite + Uvicorn + Docker PostgreSQL) |
| Production | Railway Pro |
| Domain | patherly.com (api.patherly.com for backend) |
---
## System Architecture
```
┌─────────────────────────────────────────────────────┐
│ Frontend (React) │
│ - Tree Navigation UI │
│ - Tree Editor │
│ - Session Management │
│ - Export Functionality │
└─────────────────┬───────────────────────────────────┘
│ REST API (JSON)
┌─────────────────┴───────────────────────────────────┐
│ Backend (Python FastAPI) │
│ - Authentication & Authorization │
│ - Tree CRUD Operations │
│ - Session Tracking │
│ - Export Generation │
│ - File Upload/Storage (planned) │
└─────────────────┬───────────────────────────────────┘
┌─────────────────┴───────────────────────────────────┐
│ Database (PostgreSQL) │
│ - Trees (JSONB structure) │
│ - Sessions (path tracking) │
│ - Users & Teams │
│ - Attachments Metadata │
└──────────────────────────────────────────────────────┘
```
---
## Database Schema
### Users Table
```sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL DEFAULT 'engineer', -- admin, engineer, viewer
team_id UUID REFERENCES teams(id),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_login TIMESTAMP WITH TIME ZONE
);
```
### Teams Table
```sql
CREATE TABLE teams (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```
### Trees Table
```sql
CREATE TABLE trees (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
description TEXT,
category VARCHAR(100),
tree_structure JSONB NOT NULL,
author_id UUID REFERENCES users(id),
team_id UUID REFERENCES teams(id),
is_active BOOLEAN DEFAULT true,
version INTEGER DEFAULT 1,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
usage_count INTEGER DEFAULT 0
);
CREATE INDEX idx_trees_category ON trees(category);
CREATE INDEX idx_trees_search ON trees USING gin(to_tsvector('english', name || ' ' || description));
```
### Sessions Table
```sql
CREATE TABLE sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tree_id UUID REFERENCES trees(id),
user_id UUID REFERENCES users(id),
tree_snapshot JSONB NOT NULL,
path_taken JSONB NOT NULL,
decisions JSONB NOT NULL,
started_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
completed_at TIMESTAMP WITH TIME ZONE,
ticket_number VARCHAR(100),
client_name VARCHAR(255),
exported BOOLEAN DEFAULT false
);
```
### Attachments Table
```sql
CREATE TABLE attachments (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID REFERENCES sessions(id),
node_id VARCHAR(100),
file_name VARCHAR(255) NOT NULL,
file_type VARCHAR(50),
file_size INTEGER,
storage_path VARCHAR(500),
uploaded_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
```
---
## API Endpoints
### Authentication
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/v1/auth/register` | Register new user |
| POST | `/api/v1/auth/login` | Login (form data) |
| POST | `/api/v1/auth/login/json` | Login (JSON body) |
| POST | `/api/v1/auth/refresh` | Refresh access token |
| GET | `/api/v1/auth/me` | Get current user |
| POST | `/api/v1/auth/logout` | Logout |
### Trees
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/trees` | List trees (paginated) |
| POST | `/api/v1/trees` | Create tree |
| GET | `/api/v1/trees/categories` | Get unique categories |
| GET | `/api/v1/trees/search` | Full-text search |
| GET | `/api/v1/trees/{id}` | Get tree by ID |
| PUT | `/api/v1/trees/{id}` | Update tree |
| DELETE | `/api/v1/trees/{id}` | Soft delete tree |
### Sessions
| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/v1/sessions` | List user's sessions |
| POST | `/api/v1/sessions` | Start new session |
| GET | `/api/v1/sessions/{id}` | Get session |
| PUT | `/api/v1/sessions/{id}` | Update session |
| POST | `/api/v1/sessions/{id}/complete` | Mark complete |
| POST | `/api/v1/sessions/{id}/export` | Export (md/txt/html) |
---
## Data Structures
### Tree Structure (JSONB)
```json
{
"id": "root",
"type": "decision",
"question": "Can you ping the server?",
"help_text": "Run: ping servername",
"options": [
{ "label": "Yes", "value": "yes", "next_node_id": "node_2" },
{ "label": "No", "value": "no", "next_node_id": "node_network" }
],
"children": [
{
"id": "node_2",
"type": "action",
"title": "Check service status",
"description": "Verify the service is running",
"commands": ["Get-Service -Name 'ServiceName'"],
"next_node_id": "node_3"
},
{
"id": "node_3",
"type": "solution",
"title": "Issue Resolved",
"description": "Service restarted successfully",
"resolution_steps": ["Document the fix", "Update ticket"]
}
]
}
```
### Session Decision (JSONB array item)
```json
{
"node_id": "node_1",
"question": "Can you ping the VDA?",
"answer": "yes",
"notes": "Ping successful, 2ms response time",
"timestamp": "2026-01-22T14:31:00Z",
"attachments": []
}
```
---
## Security
### Authentication
- JWT tokens: 15-minute access, 7-day refresh
- Passwords: bcrypt with cost factor 12
- Role-based access: admin, engineer, viewer
### API Security
- CORS configured for frontend origins
- Rate limiting planned
- Input validation via Pydantic
- SQL injection prevention via SQLAlchemy ORM
### Data Protection
- HTTPS in production
- Timezone-aware timestamps (UTC storage)
- Soft deletes for trees (is_active flag)
---
## Deployment
### Development Setup
```powershell
# Terminal 1: Database
docker start patherly_postgres
# Terminal 2: Backend
cd backend
.\venv\Scripts\activate
uvicorn app.main:app --reload
# Terminal 3: Frontend
cd frontend
npm run dev
```
### Production (Railway)
- **Database:** Railway managed PostgreSQL
- **Backend:** api.patherly.com
- **Frontend:** patherly.com
- **Environment:** PR environments for testing
### Key Configuration
```env
# Backend .env
DATABASE_URL=postgresql+asyncpg://user:pass@host:5432/patherly
SECRET_KEY=your-secret-key
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
# Frontend .env
VITE_API_URL=http://localhost:8000
```
---
## File Structure
```
patherly/
├── backend/
│ ├── app/
│ │ ├── api/v1/endpoints/ # Route handlers
│ │ ├── core/ # Config, security, logging
│ │ ├── models/ # SQLAlchemy models
│ │ └── schemas/ # Pydantic schemas
│ ├── alembic/ # Migrations
│ ├── tests/ # pytest tests
│ └── scripts/ # Seed scripts
├── frontend/
│ ├── src/
│ │ ├── api/ # API client
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ └── store/ # Zustand stores
│ └── public/
└── docs/ # Documentation
```
---
*For current project status, see [CURRENT-STATE.md](./CURRENT-STATE.md)*
*For development setup, see [QUICK-START.md](./QUICK-START.md)*
*For known issues, see [LESSONS-LEARNED.md](./LESSONS-LEARNED.md)*

455
docs/archive/BACKLOG.md Normal file
View File

@@ -0,0 +1,455 @@
# Backlog - Future Features & Ideas
> **Purpose:** Long-term feature ideas, "what if" concepts, and parking lot items.
> **Note:** These are brainstorm items, not committed roadmap. Evaluate based on user demand and business impact.
> **Last Updated:** February 2, 2026
---
## Table of Contents
1. [Dynamic Script Generation](#dynamic-script-generation)
2. [Beyond Service Desk - Department Expansion](#beyond-service-desk---department-expansion)
3. [Tree Collaboration & Sharing](#tree-collaboration--sharing)
4. [Integration Ideas](#integration-ideas)
5. [Mobile & Accessibility](#mobile--accessibility)
6. [Gamification & Training](#gamification--training)
7. [Advanced Analytics](#advanced-analytics)
8. [AI-Powered Features](#ai-powered-features)
9. [Parking Lot - Quick Ideas](#parking-lot---quick-ideas)
10. [Long-Term Vision](#long-term-vision)
11. [Idea Evaluation Criteria](#idea-evaluation-criteria)
---
## Dynamic Script Generation
### Concept: Trees That Generate PowerShell Scripts
Instead of just guiding a tech through troubleshooting steps, trees could COLLECT information and OUTPUT executable scripts.
**Example Scenario: New User Onboarding**
A ticket comes in: "New hire starting Monday - John Smith, Marketing department"
Traditional approach:
1. Tech manually creates AD user
2. Tech looks up which groups Marketing needs
3. Tech adds user to groups one by one
4. Tech moves user to correct OU
5. Tech documents what they did
**Script Generation approach:**
```
┌─────────────────────────────────────────────────────────────┐
│ NEW USER ONBOARDING TREE │
├─────────────────────────────────────────────────────────────┤
│ Step 1: Enter user details │
│ First Name: [John_____________] │
│ Last Name: [Smith____________] │
│ Department: [Marketing________] ▼ │
│ │
│ Step 2: Select required groups (auto-suggested by dept) │
│ ☑ Domain Users │
│ ☑ Marketing-All │
│ ☑ SharePoint-Marketing │
│ │
│ Step 3: Confirm organizational unit │
│ OU Path: OU=Marketing,OU=Users,DC=contoso,DC=com │
│ │
│ [Generate Script] │
└─────────────────────────────────────────────────────────────┘
```
**Generated Output:**
```powershell
# New User Creation Script
# Generated by Patherly - 2026-01-28 14:32
# Ticket: #12345
$Password = Read-Host -AsSecureString "Enter initial password"
New-ADUser -Name "John Smith" `
-GivenName "John" `
-Surname "Smith" `
-SamAccountName "jsmith" `
-UserPrincipalName "jsmith@contoso.com" `
-Path "OU=Marketing,OU=Users,DC=contoso,DC=com" `
-AccountPassword $Password `
-Enabled $true
# Add to groups
@("Domain Users", "Marketing-All", "SharePoint-Marketing") | ForEach-Object {
Add-ADGroupMember -Identity $_ -Members "jsmith"
}
```
**Value Proposition:**
- Eliminates manual typing errors
- Ensures consistency across techs
- Auto-documents what was done
- Reduces training time for new hires
- Script can be reviewed before execution (safety)
### Other Script Generation Use Cases
| Use Case | Inputs Collected | Output |
|----------|------------------|--------|
| User Offboarding | Username, actions to take | Disable/remove script |
| Bulk Group Changes | User list, groups | Group membership script |
| Computer Setup | Name, department, user | Deployment script |
| Network Diagnostics | Issue description | Diagnostic collection script |
| M365 License Assignment | User, license type | PowerShell for M365 |
### Technical Considerations
**New Node Type: "Input Node"**
```typescript
interface InputNode {
type: 'input';
fields: InputField[];
validation?: ValidationRules;
next_node_id: string;
}
interface InputField {
name: string;
label: string;
type: 'text' | 'select' | 'multiselect' | 'checkbox' | 'number';
options?: string[];
variable_name: string; // used in script template
}
```
**New Node Type: "Script Output Node"**
```typescript
interface ScriptOutputNode {
type: 'script_output';
script_template: string; // PowerShell with {{variable}} placeholders
language: 'powershell' | 'bash' | 'python';
documentation_template?: string;
}
```
### Safety & Compliance Features
- **Script Review Mode:** Scripts NEVER auto-execute, always presented for review
- **Audit Trail:** Log which scripts were generated and by whom
- **Template Approval:** Senior engineers review templates before publishing
- **Environment Variables:** Store org-specific values (domain name, OU paths)
### Implementation Phases
1. **Phase 1:** Basic script output with variable substitution
2. **Phase 2:** Input collection nodes with validation
3. **Phase 3:** Smart defaults (department → group suggestions)
4. **Phase 4:** Direct execution capability (Enterprise, with approval workflows)
---
## Beyond Service Desk - Department Expansion
### Concept: Department-Specific Path Libraries
The "guided decision tree" concept applies to ANY process that benefits from consistency and documentation.
**Target Departments:**
| Department | Use Cases |
|------------|-----------|
| Service Desk | Troubleshooting (current focus) |
| Sales | Quoting, assessments, discovery |
| vCIO/Consulting | Policy creation, strategic planning |
| Onboarding | Client setup, documentation gathering |
| Finance | Contract review, billing disputes |
| HR | Employee onboarding, policy acknowledgment |
### vCIO / Consulting: Policy Builder
Guide clients through policy creation with smart templates and boilerplate language.
**Example: Acceptable Use Policy Builder**
User selects sections to include:
- ☑ Computer Use Policy
- ☑ Mobile Device Policy
- ☑ BYOD Policy
- ☑ AI Usage Policy
- ☑ Remote Work Policy
**Generated Output:** Complete, formatted policy document (Word/PDF) with:
- Professional boilerplate language
- Industry-specific compliance notes (HIPAA for healthcare, etc.)
- Signature/acknowledgment section
**Policy Types to Support:**
- Acceptable Use Policy (AUP)
- Information Security Policy
- Password Policy
- Data Classification Policy
- Incident Response Policy
- BYOD Policy
- AI/Generative AI Policy
**Value Proposition:**
- vCIOs generate client policies in minutes, not hours
- Consistent, professional output
- Industry-specific compliance built-in
- Upsell opportunity: "Policy Review" as a service
### Sales: Quote Builder & Assessment Paths
Guide sales reps through discovery with consistent methodology that surfaces upsell opportunities.
**Assessment Types:**
1. **Security Assessment** - Endpoint protection, MFA, training gaps
2. **Backup Assessment** - Frequency, retention, testing procedures
3. **Hardware Assessment** - Workstation age, server infrastructure, warranties
4. **Compliance Assessment** - HIPAA, PCI, documentation status
5. **Cloud Readiness Assessment** - Migration complexity, bandwidth needs
**Generated Outputs:**
- Gap Analysis Report (client-facing)
- Quote Worksheet (internal)
- Proposal Content (client-facing)
### Client Onboarding Paths
Structured onboarding ensuring nothing is missed:
- Contact gathering (technical, billing, decision makers)
- Credentials collection (secure vault integration)
- Documentation intake (passwords, network diagrams)
- Standards configuration (naming conventions, security policies)
- Tool deployment checklist
- Handoff to service desk
**Output:** Populated documentation templates, IT Glue/Hudu import-ready data
---
## Tree Collaboration & Sharing
### Public Tree Gallery
- Users publish trees to community gallery
- Rating and review system
- "Verified" badge for quality trees
- Fork and customize
### Tree Marketplace
- Premium trees from experts
- Revenue share model (70/30)
- Subscription access to premium library
### Tree Inheritance
- Company-wide "official" trees
- Teams create local variations
- Changes can be proposed upstream
- Version control and diff viewing
---
## Integration Ideas
### PSA Deep Integration
- Create ticket from tree resolution
- Auto-populate ticket fields from session
- Link session to existing ticket
- Pull ticket context into tree suggestions
**Target PSAs:** ConnectWise, Kaseya, Autotask, ServiceNow
### RMM Integration
- Pull device info into tree context
- "This computer has X installed, skip to step Y"
- Trigger RMM scripts from tree actions
- Asset-aware troubleshooting
**Target RMMs:** Datto, ConnectWise Automate, NinjaRMM
### Documentation Integration
- Link tree nodes to IT Glue/Hudu articles
- Auto-create documentation from resolved sessions
- Sync tree content with knowledge base
### Communication Integration
- Slack/Teams notifications for escalations
- Share session summary to channel
- Request help from team within tree
---
## Mobile & Accessibility
### Mobile App (PWA Enhancement)
- Offline tree access
- Voice input for hands-free use
- Camera integration for error screenshots
- Push notifications for shared sessions
### Voice-Guided Mode
- Read steps aloud
- Voice commands to navigate
- Useful for field techs with hands busy
- Accessibility for vision-impaired users
---
## Gamification & Training
### Tech Leaderboards
- Trees completed
- Resolution time improvements
- Contribution to tree improvements
- Points and badges
### Training Mode
- Practice trees without affecting stats
- Simulated scenarios
- Quiz mode with wrong-path feedback
- Certification preparation
### Onboarding Tracks
- Structured learning paths for new hires
- Progress tracking
- Manager visibility into training progress
---
## Advanced Analytics
### Predictive Issue Alerts
- "VPN issues spike on Mondays after updates"
- Proactive notifications to prepare
- Trend forecasting
### Cost Attribution
- Estimate time spent per issue type
- Calculate cost of common problems
- ROI justification for fixes
### Comparative Analytics
- Benchmark against anonymized industry data
- "Your password reset time is 20% faster than average"
- Identify improvement opportunities
---
## AI-Powered Features
### Conversational Interface
- Chat with AI about an issue
- AI suggests relevant trees
- Natural language navigation
### Auto-Tree Generation
- Record a senior tech explaining a fix
- AI generates tree structure from transcript
- Review and publish
### Predictive Resolution
- AI predicts likely resolution before tree starts
- "Based on the description, this is probably X (85% confidence)"
- Option to jump to likely solution
### Import from Text/Documentation
- Paste existing runbook or documentation
- AI parses and creates tree structure
- Review and refine
---
## Parking Lot - Quick Ideas
*Quick-capture ideas to evaluate later:*
- [ ] Browser extension to capture screenshots into sessions
- [ ] QR codes on physical equipment linking to relevant trees
- [ ] Customer-facing trees (end-user self-service)
- [ ] Tree templates for common scenarios
- [ ] Scheduled tree reminders (monthly server maintenance checklist)
- [ ] Integration with monitoring tools (trigger tree from alert)
- [ ] Multi-language tree support
- [ ] Conditional logic based on time of day / day of week
- [ ] SLA timers visible during session
- [ ] Escalation workflows with approval chains
- [ ] Custom note formatting templates for different ticket systems
- [ ] "Options on the go" - select pre-made steps mid-tree and jump to relevant point
- [ ] Import plan function - write in text format and import as tree
---
## Long-Term Vision (Year 2+)
### Product Evolution
- Self-learning system (trees improve automatically based on usage)
- Voice-guided troubleshooting (hands-free operation)
- AR/VR support (on-site equipment identification)
- AI co-pilot (real-time suggestions during troubleshooting)
### Market Expansion
- Vertical-specific tree libraries (healthcare IT, financial services, education)
- Certification program for tree authors
- Professional services (custom tree development)
- Training and consultation services
### Platform Maturity
- 99.9% uptime SLA
- Global CDN deployment
- Advanced compliance (SOC 2, ISO 27001)
- Enterprise support tiers
- White-glove onboarding
---
## Idea Evaluation Criteria
When evaluating which ideas to pursue:
| Criteria | Weight | Questions |
|----------|--------|-----------|
| User demand | High | Are users asking for this? |
| Revenue impact | High | Will this drive upgrades or reduce churn? |
| Differentiation | Medium | Does this set us apart from alternatives? |
| Development effort | Medium | How long to build MVP? |
| Maintenance burden | Medium | Ongoing cost to support? |
| Strategic fit | Medium | Does this align with our vision? |
---
## How to Add Ideas
When adding new ideas to this document:
1. **Describe the concept** - What is it? Why would users want it?
2. **Provide an example** - Concrete scenario showing the feature in action
3. **Note technical considerations** - What would need to change?
4. **Estimate complexity** - Simple / Medium / Complex
5. **Identify dependencies** - What needs to exist first?
---
*This is a living document. Add ideas freely, evaluate periodically, and move promising concepts to GitHub Issues when ready to implement.*

View File

@@ -0,0 +1,719 @@
# Claude Code Setup Reference for Patherly
This document catalogs all tools, plugins, and MCP servers available to Claude Code when developing Patherly, along with guidelines for their effective use.
**Last Updated**: 2026-01-29
**Project**: Patherly
**Working Directory**: `c:\Dev\Projects\patherly`
**Platform**: Windows (win32)
**IDE**: VSCode with Claude Code extension
---
## Core Built-In Tools
### File Operations
#### Read
- **Purpose**: Read file contents from the filesystem
- **Capabilities**:
- Reads up to 2000 lines by default
- Supports offset/limit for large files
- Can read images (PNG, JPG), PDFs, and Jupyter notebooks
- Returns content with line numbers
- **When to use**: Always read files before editing them; use for examining code, configs, or documentation
#### Edit
- **Purpose**: Perform exact string replacements in files
- **Capabilities**:
- Replaces `old_string` with `new_string`
- Supports `replace_all` for renaming variables
- Preserves indentation
- **When to use**: Prefer editing over writing new files; ideal for targeted changes
- **Requirements**: Must read file first before editing
#### Write
- **Purpose**: Create new files or overwrite existing ones
- **Capabilities**: Writes complete file content
- **When to use**: Only for creating genuinely new files; avoid for existing files (use Edit instead)
- **Requirements**: Must read file first if it exists
#### NotebookEdit
- **Purpose**: Edit Jupyter notebook (.ipynb) cells
- **Capabilities**:
- Replace, insert, or delete cells
- Supports code and markdown cells
- **When to use**: Working with Jupyter notebooks in the project
### Search & Discovery
#### Glob
- **Purpose**: Fast file pattern matching
- **Capabilities**:
- Supports glob patterns like `**/*.js`, `src/**/*.ts`
- Returns files sorted by modification time
- **When to use**: Finding files by name patterns; use for specific needle queries
- **Example**: `**/*.py` to find all Python files
#### Grep
- **Purpose**: Powerful content search (built on ripgrep)
- **Capabilities**:
- Full regex support
- Filter by glob or file type
- Output modes: content, files_with_matches, count
- Context lines (-A, -B, -C)
- Multiline matching support
- **When to use**: Searching for code patterns, function definitions, or specific strings
- **Important**: Use Task with Explore agent for open-ended exploratory searches
### Execution & System
#### Bash
- **Purpose**: Execute bash commands
- **Capabilities**:
- Git operations
- Package management (npm, pip, etc.)
- Build commands
- Testing
- System operations
- **When to use**: Terminal operations, git, npm, docker, but NOT for file reading/searching (use specialized tools)
- **Best practices**:
- Use `&&` for sequential dependent commands
- Quote paths with spaces
- Avoid `cd`; use absolute paths instead
- Never skip git hooks unless explicitly requested
#### TaskOutput
- **Purpose**: Retrieve output from running/completed background tasks
- **When to use**: Check status of background shells or agents
#### TaskStop
- **Purpose**: Stop running background tasks
- **When to use**: Terminate long-running processes
### Planning & Task Management
#### TodoWrite
- **Purpose**: Create and manage structured task lists
- **Capabilities**:
- Track tasks with states: pending, in_progress, completed
- Organize complex multi-step work
- **When to use**:
- Complex tasks with 3+ steps
- Multi-file changes
- User provides multiple tasks
- Before starting work on each task
- **Best practice**: Mark todos completed immediately after finishing; maintain exactly ONE in_progress task at a time
#### EnterPlanMode / ExitPlanMode
- **Purpose**: Enter planning mode for implementation design
- **When to use**:
- New feature implementation
- Multiple valid approaches exist
- Architectural decisions needed
- Multi-file changes
- Unclear requirements
- **When NOT to use**: Simple one-line fixes, trivial tasks, pure research
#### AskUserQuestion
- **Purpose**: Ask user questions during execution
- **Capabilities**:
- Multiple choice questions (2-4 options)
- Multi-select support
- Collects user preferences and clarifications
- **When to use**: Need clarification on requirements, implementation choices, or ambiguous instructions
### Web & Information
#### WebFetch
- **Purpose**: Fetch and analyze web content
- **Capabilities**:
- Converts HTML to markdown
- 15-minute cache
- **Limitations**: WILL FAIL for authenticated/private URLs
- **When to use**: Public documentation, articles, reference materials
- **Note**: For GitHub URLs, prefer `gh` CLI via Bash
#### WebSearch
- **Purpose**: Search the web for current information
- **Capabilities**:
- Access to up-to-date information beyond knowledge cutoff
- Domain filtering (allowed/blocked)
- **Requirements**: MUST include "Sources:" section with markdown links in response
- **When to use**: Current events, recent documentation, external references
#### ToolSearch
- **Purpose**: Load deferred MCP tools before use
- **Capabilities**:
- Keyword search mode (e.g., "slack", "notebook")
- Direct selection mode (e.g., "select:NotebookEdit")
- Required keyword mode (e.g., "+linear create issue")
- **When to use**: MANDATORY before calling any deferred/MCP tool
- **Important**: This is a BLOCKING requirement - must load tools before calling them
---
## Specialized Agents (via Task Tool)
The Task tool launches specialized agents for complex work. Each agent type has specific capabilities:
### Bash Agent
- **Specialty**: Command execution
- **Tools**: Bash only
- **When to use**: Git operations, complex command sequences
### general-purpose Agent
- **Specialty**: Complex research and multi-step tasks
- **Tools**: All tools
- **When to use**: Complex questions, keyword searches requiring multiple attempts
### Explore Agent
- **Specialty**: Fast codebase exploration
- **Tools**: Read-only tools (Glob, Grep, Read, etc.)
- **Thoroughness levels**: quick, medium, very thorough
- **When to use**:
- "Where are errors handled?"
- "How do API endpoints work?"
- "What is the codebase structure?"
- **Critical**: Use this instead of manual Glob/Grep for exploratory searches
### Plan Agent
- **Specialty**: Implementation planning and architecture design
- **Tools**: Read-only tools
- **When to use**: Design implementation strategy, identify critical files, consider architectural trade-offs
### feature-dev Agents
- **code-architect**: Design feature architectures
- **code-explorer**: Analyze existing features and patterns
- **code-reviewer**: Review code for bugs and quality issues
---
## Available Skills (via Skill Tool)
Skills are invoked when users reference slash commands (e.g., `/commit`).
### feature-dev:feature-dev
- **Purpose**: Guided feature development with architecture focus
- **When to use**: Building new features from scratch
### frontend-design:frontend-design
- **Purpose**: Create production-grade frontend interfaces
- **When to use**: Building web components, pages, or applications
- **Goal**: Avoid generic AI aesthetics; create polished, distinctive designs
### Figma Integration Skills
- **figma:code-connect-components**: Map Figma designs to code components
- **figma:create-design-system-rules**: Generate custom design system rules
- **figma:implement-design**: Translate Figma designs to production code
- **Requirement**: Figma MCP server connection
---
## MCP Servers (Deferred Tools)
These tools must be loaded via ToolSearch before use.
### GitHub MCP Server
**Prefix**: `mcp__github__*`
**Available Operations**:
- **Repository**: create, fork, search repositories
- **Files**: get contents, create/update files, push files
- **Branches**: create, list commits
- **Issues**: create, list, update, get, add comments, search
- **Pull Requests**: create, list, get, merge, review, get files/status/comments
- **Search**: code, issues, users
**When to use**: GitHub operations beyond what `gh` CLI provides
### Filesystem MCP Server
**Prefix**: `mcp__filesystem__*`
**Available Operations**:
- **Read**: read_file, read_text_file, read_media_file, read_multiple_files
- **Write**: write_file, edit_file
- **Directory**: create, list, tree, list_with_sizes
- **Operations**: move, search files, get file info
- **Management**: list_allowed_directories
**When to use**: Complex filesystem operations; prefer built-in Read/Write/Edit for simple operations
### MS365 MCP Server
**Prefix**: `mcp__ms365__*`
**Available Operations**:
- **Authentication**: login, logout, verify, list/select/remove accounts
- **Teams**: chat operations, channel messages, team management
- **OneDrive**: file operations, Excel operations (worksheets, charts, ranges)
- **Outlook**: mail operations, calendar events, contacts
- **SharePoint**: site operations, lists, items
- **Planner**: tasks and plans
- **OneNote**: notebooks, sections, pages
- **Todo**: task lists and tasks
**When to use**: Integration with Microsoft 365 services
### PostgreSQL MCP Server
**Prefix**: `mcp__postgres__*`
**Connection Details**:
- **Connection String**: `postgresql://postgres:postgres@localhost:5432/patherly`
- **Container Name**: `patherly_postgres`
- **Database Version**: PostgreSQL 16 Alpine
- **Docker Requirement**: Docker Desktop must be running
**Available Operations**:
- **Query**: Execute SQL queries directly
- **Schema Inspection**: View tables, columns, indexes, constraints
- **JSONB Analysis**: Inspect tree_structure and session path data
- **Migration Verification**: Confirm Alembic migrations applied correctly
- **Data Debugging**: Check auth tokens, user roles, tree categories
- **Performance**: Analyze query plans, check indexes
**When to use**:
- Debugging database issues
- Inspecting JSONB tree structures in `trees` table
- Verifying user authentication data
- Checking session path tracking
- Validating migration results
- Analyzing full-text search indexes
- Direct SQL queries for complex operations
**Common Use Cases**:
```sql
-- View all active trees with their categories
SELECT id, name, category, version, is_active, usage_count FROM trees WHERE is_active = true;
-- Inspect JSONB tree structure
SELECT id, name, tree_structure FROM trees WHERE id = '<uuid>';
-- Check user accounts
SELECT id, email, name, role, team_id, created_at FROM users;
-- View active sessions with user and tree info
SELECT s.id, u.email, t.name, s.ticket_number, s.started_at, s.completed_at
FROM sessions s
JOIN users u ON s.user_id = u.id
JOIN trees t ON s.tree_id = t.id
WHERE s.completed_at IS NULL;
-- Analyze session path tracking (JSONB)
SELECT id, ticket_number, path_taken, decisions FROM sessions WHERE id = '<uuid>';
```
### Fetch MCP Server
**Status**: ❌ Failed to install
**Alternative**: Use Bash tool with `curl` or PowerShell's `Invoke-RestMethod` for API testing
**Example - Testing FastAPI endpoints**:
```bash
# PowerShell example
$response = Invoke-RestMethod -Uri "http://localhost:8000/api/v1/trees" -Method GET -Headers @{"Authorization"="Bearer <token>"}
# Curl example (if available)
curl -X GET "http://localhost:8000/api/v1/trees" -H "Authorization: Bearer <token>"
```
**When to use Bash for API testing**:
- Testing authentication flow (register, login, refresh)
- Verifying endpoint responses
- Testing file uploads for attachments
- Validating export formats (md/txt/html)
- Checking error handling
---
## Project-Specific Context: Patherly
### Project Overview
**Patherly** is a troubleshooting decision tree web application designed for MSP (Managed Service Provider) engineers. The application allows engineers to create, manage, and navigate through decision trees for common IT support scenarios, improving troubleshooting consistency and efficiency.
### Technology Stack
**Backend (Complete)**:
- **Framework**: FastAPI (Python)
- **Database**: PostgreSQL 16 Alpine
- **ORM**: SQLAlchemy 2.0 (async)
- **Authentication**: JWT tokens (15-min access, 7-day refresh)
- **Password Hashing**: bcrypt (via passlib, pinned to 4.1.2 for compatibility)
- **API Endpoints**: 18 RESTful endpoints
- **Containerization**: Docker (patherly_postgres container)
- **Migrations**: Alembic
**Frontend (Complete + Tree Editor)**:
- **Framework**: React 18 + Vite + TypeScript
- **Styling**: Tailwind CSS + shadcn/ui CSS variables
- **State Management**: Zustand with immer + zundo (undo/redo)
- **Routing**: React Router v6
- **API Client**: Axios with token interceptors
- **Status**: Core features complete, Tree Editor implemented
**Infrastructure**:
- **Development**: Local Docker PostgreSQL
- **Deployment Target**: Render (dev) / Railway Pro (production)
### Database Schema
**5 Core Tables**:
1. **users**: User accounts with roles (admin, engineer, viewer), team associations
2. **teams**: Team groupings for multi-tenant support
3. **trees**: Decision trees with JSONB `tree_structure` field, versioning, categories
4. **sessions**: Troubleshooting sessions with path tracking (JSONB)
5. **attachments**: File attachments linked to sessions
**Key Features**:
- UUID primary keys via PostgreSQL `gen_random_uuid()`
- JSONB for flexible tree structures and session paths
- Full-text search using PostgreSQL `to_tsvector`
- Soft deletes for trees (`is_active` flag - set to false on delete)
- Timezone-aware timestamps (all DateTime fields use `DateTime(timezone=True)` with UTC storage)
### Current Development Phase
**Phase 1: Backend + Frontend MVP** - ✅ **COMPLETE**
- All 18 API endpoints implemented and verified
- Database schema finalized with timezone-aware timestamps
- Authentication system working (JWT with bcrypt, role-based access)
- 40+ integration tests (all passing) with comprehensive coverage
- Production logging with correlation IDs
- React frontend with tree navigation, session management, export
**Phase 2: Tree Editor** - 🔄 **IN PROGRESS**
- ✅ Zustand store with immer middleware + zundo (undo/redo)
- ✅ Form-based node editing (Decision, Action, Solution types)
- ✅ Visual tree preview with solution connection indicators
- ✅ NodePicker with type-grouped dropdown
- ✅ SharedLinksMap for detecting nodes with multiple sources
- ✅ Modal with scrollable content, fixed header/footer
- ✅ Markdown rendering in session player and node editor
- ✅ Dark mode / theme toggle
- ⏳ Validation polish (required fields, orphan detection)
**Phase 2 Remaining** - ⏳ **Planned**
- Team management features
- Mobile responsive improvements
- ~~User preferences (dark mode)~~ ✅ **COMPLETE**
### Backend File Structure
```
backend/
├── alembic/ # Database migrations
│ ├── versions/
│ │ └── 001_initial_schema.py
│ └── env.py
├── app/
│ ├── api/
│ │ ├── endpoints/
│ │ │ ├── auth.py # /api/v1/auth/* (register, login, refresh)
│ │ │ ├── trees.py # /api/v1/trees/* (CRUD, search)
│ │ │ └── sessions.py # /api/v1/sessions/* (tracking, export)
│ │ ├── deps.py # Auth dependencies (JWT validation)
│ │ └── router.py # Main API router
│ ├── core/
│ │ ├── config.py # Pydantic settings
│ │ ├── database.py # Async SQLAlchemy setup
│ │ ├── security.py # JWT + bcrypt utilities
│ │ ├── logging_config.py # Structured logging configuration
│ │ └── middleware.py # Request logging middleware
│ ├── models/ # SQLAlchemy models (timezone-aware)
│ ├── schemas/ # Pydantic schemas
│ └── main.py # FastAPI app entry point
├── tests/ # Integration tests (40+ tests)
├── logs/ # Log files (created at runtime)
├── docker-compose.yml # PostgreSQL container definition
└── requirements.txt # Production dependencies
```
### Frontend File Structure
```
frontend/
├── src/
│ ├── api/ # API client layer
│ │ ├── client.ts # Axios instance with auth interceptors
│ │ ├── auth.ts # Auth endpoints
│ │ ├── trees.ts # Tree endpoints
│ │ └── sessions.ts # Session endpoints
│ ├── components/
│ │ ├── common/
│ │ │ └── Modal.tsx # Reusable modal (scrollable body, fixed header/footer)
│ │ ├── layout/ # AppLayout, ProtectedRoute
│ │ ├── tree-editor/ # Tree Editor components
│ │ │ ├── TreeEditorLayout.tsx # Split-view container
│ │ │ ├── TreeMetadataForm.tsx # Name, description, category
│ │ │ ├── NodeList.tsx # Node list with CRUD actions
│ │ │ ├── NodeEditorModal.tsx # Modal wrapper for node editing
│ │ │ ├── NodeFormDecision.tsx # Decision node fields
│ │ │ ├── NodeFormAction.tsx # Action node fields
│ │ │ ├── NodeFormResolution.tsx # Solution node fields
│ │ │ ├── DynamicArrayField.tsx # Reusable array input
│ │ │ └── NodePicker.tsx # Type-grouped node selector
│ │ └── tree-preview/ # Visual preview components
│ │ ├── TreePreviewPanel.tsx # Preview container + SharedLinksMap
│ │ └── TreePreviewNode.tsx # Node cards with solution indicators
│ ├── pages/
│ │ ├── TreeEditorPage.tsx # /trees/new and /trees/:id/edit
│ │ ├── TreeLibraryPage.tsx # Tree browsing
│ │ ├── TreeNavigationPage.tsx # Tree traversal
│ │ └── ... # Other pages
│ ├── store/
│ │ ├── authStore.ts # Auth state (Zustand + persist)
│ │ └── treeEditorStore.ts # Tree editor state (Zustand + immer + zundo)
│ ├── types/ # TypeScript types
│ │ ├── tree.ts # TreeStructure, TreeNode, etc.
│ │ └── index.ts # Barrel exports
│ ├── router.tsx # React Router configuration
│ └── main.tsx # Entry point
├── tailwind.config.js
└── vite.config.ts
```
### Development Workflow
**Starting the Backend**:
```bash
# 1. Start PostgreSQL container
cd backend
docker-compose up -d
# 2. Activate Python virtual environment
venv\Scripts\activate # Windows
# source venv/bin/activate # Linux/Mac
# 3. Run migrations (if not already applied)
alembic upgrade head
# 4. Start FastAPI development server
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# 5. Access API documentation
# http://localhost:8000/api/docs
```
**Database Connection**:
- **Host**: localhost:5432
- **Database**: patherly
- **User**: postgres
- **Password**: postgres
- **Container**: patherly_postgres
### Recent Work & Git History
**Recent Commits**:
```
a3efe68 Committing before moving to local disk
a6fc86c Pin bcrypt version to 4.1.2 for passlib compatibility
fa632da Fix backend: add passlib/bcrypt, fix datetime timezone issues
```
**Key Issues Resolved** (January 28, 2026):
- **DateTime Bug Fix**: Fixed timezone-naive/timezone-aware mixing that caused Internal Server Errors
- Updated all models to use `DateTime(timezone=True)` with UTC storage
- Changed all datetime defaults to `lambda: datetime.now(timezone.utc)`
- Affects: Session completion, session updates, all timestamp fields
- **Production Logging**: Added comprehensive logging with request correlation IDs and log rotation
- **Integration Tests**: Created 40+ tests covering all endpoints with good coverage
- **Schema Documentation**: Corrected `is_active` vs `is_deleted` column references
- **Bcrypt Compatibility**: Version pinned to 4.1.2 for passlib compatibility
**Current Repository State**:
- Branch: main
- Working tree: Multiple modified files (models, main.py, tests/, PROGRESS.md, CLAUDE-SETUP.md)
- Backend: **Fully tested and operational** - all 18 endpoints verified
- Tests: 40+ integration tests with pytest and coverage reporting
- Logging: Production-ready with correlation IDs and rotation
- Frontend: Not started
### File Reference Format
When referencing code in VSCode, use markdown links:
- Files: `[filename.py](backend/app/api/endpoints/auth.py)`
- Specific lines: `[auth.py:42](backend/app/api/endpoints/auth.py#L42)`
- Line ranges: `[auth.py:42-51](backend/app/api/endpoints/auth.py#L42-L51)`
- Folders: `[backend/app/api/](backend/app/api/)`
### Important Reference Files
- **[PROGRESS.md](PROGRESS.md)**: Development progress tracker
- **[02-TECHNICAL-ARCHITECTURE.md](02-TECHNICAL-ARCHITECTURE.md)**: Complete technical specification
- **[05-QUESTIONS-AND-ACTION-ITEMS.md](05-QUESTIONS-AND-ACTION-ITEMS.md)**: Design decisions log
- **[TS-EXAMPLES.md](TS-EXAMPLES.md)**: 5 example troubleshooting trees for Phase 1b
- **[backend/README.md](backend/README.md)**: Backend setup instructions
---
## Development Guidelines
### General Workflow
1. **Read First**: Always read files before editing
2. **Plan Complex Tasks**: Use TodoWrite for multi-step work
3. **Use Specialized Tools**: Prefer dedicated tools over bash commands for file operations
4. **Explore Efficiently**: Use Task with Explore agent for codebase exploration
5. **Parallel Execution**: Make independent tool calls in parallel when possible
### Code Modification Principles
- **Avoid Over-Engineering**: Only make requested changes
- **No Premature Abstraction**: Don't create utilities for one-time operations
- **Security First**: Watch for command injection, XSS, SQL injection, OWASP Top 10
- **Simplicity**: Keep solutions focused and minimal
- **No Unnecessary Additions**: Don't add error handling for impossible scenarios
### Git Best Practices
- **Never** update git config
- **Never** run destructive commands (push --force, reset --hard) without explicit request
- **Never** skip hooks (--no-verify, --no-gpg-sign)
- **Always** create NEW commits (don't amend unless requested)
- **Prefer** staging specific files over `git add -A` or `git add .`
- **Only commit** when explicitly requested
- **Include** co-author tag: `Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>`
### Pull Request Workflow
1. Run `git status`, `git diff`, check branch state
2. Analyze ALL commits from branch divergence (not just latest)
3. Keep PR title under 70 characters
4. Use HEREDOC for PR body with format:
```
## Summary
<1-3 bullet points>
## Test plan
[Checklist of testing TODOs]
🤖 Generated with [Claude Code](https://claude.com/claude-code)
```
### Communication Style
- **Concise**: Short, focused responses for CLI display
- **No Emojis**: Unless explicitly requested
- **No Time Estimates**: Never predict how long tasks will take
- **Objective**: Technical accuracy over validation
- **Direct**: Use markdown formatting, output text directly (not via echo/bash)
### When to Ask for Help
- **User Questions**: Use AskUserQuestion for clarifications
- **Planning**: Use EnterPlanMode for complex implementation decisions
- **Feedback**: Direct users to <https://github.com/anthropics/claude-code/issues>
---
## Quick Reference: Tool Selection Decision Tree
```
Need to find files by name pattern?
→ Use Glob
Need to search for code content?
→ Specific query? → Use Grep
→ Exploratory search? → Use Task (Explore agent)
Need to read a file?
→ Use Read (not cat)
Need to modify existing file?
→ Use Edit (not sed/awk)
Need to create new file?
→ Use Write (not echo/heredoc)
Need to execute command/git/npm?
→ Use Bash
Need to plan complex implementation?
→ Use EnterPlanMode
Need to track multi-step task?
→ Use TodoWrite
Need GitHub/MS365/filesystem MCP operations?
→ First: ToolSearch to load tool
→ Then: Call the loaded MCP tool
Need to ask user a question?
→ Use AskUserQuestion
```
---
## Notes for Future Sessions
- **Context Persistence**: Conversations have unlimited context through automatic summarization
- **Tool Results**: May include `<system-reminder>` tags with useful information
- **Model**: Powered by Claude Sonnet 4.5 (claude-sonnet-4-5-20250929)
- **Knowledge Cutoff**: January 2025
- **Current Date**: Always use 2026 in current date calculations
---
## Security Policy
**Defensive Security Only**
- Assist with security analysis, detection rules, vulnerability explanations
- Create defensive tools and security documentation
- **Refuse**: Code for malicious use, credential harvesting, bulk SSH key/cookie/wallet crawling
---
*This reference guide should be consulted at the start of each session to ensure effective use of all available tools and maintain consistency with project conventions.*

View File

@@ -0,0 +1,234 @@
# Implementation Summary: Issue #34 - Tree Library Full View System
**Date:** February 7, 2026
**Status:** ✅ Complete
**Issue:** #34 - Tree Library Full View System (Grid/List/Table)
## Overview
Implemented a comprehensive view control system for the Tree Library page, allowing users to switch between Grid, List, and Table views with flexible sorting options. All preferences are persisted to localStorage.
## Changes Implemented
### Backend Changes
#### 1. API Enhancement (trees.py)
- **File:** `backend/app/api/endpoints/trees.py`
- **Changes:**
- Added `sort_by` query parameter to `GET /api/v1/trees` endpoint
- Implemented sorting logic for 6 sort options:
- `usage_count` (default) - Most used trees
- `updated_at` - Recently updated
- `created_at` - Recently created
- `name` - Alphabetical A-Z
- `name_desc` - Alphabetical Z-A
- `version` - By version number
- Maintains backward compatibility (defaults to usage_count)
#### 2. Tests Added
- **File:** `backend/tests/test_trees.py`
- **New Test:** `test_list_trees_sorting`
- Creates multiple trees with different attributes
- Tests all 6 sorting options
- Verifies sort order correctness
- All 13 tree tests pass ✅
### Frontend Changes
#### 1. User Preferences Store
- **File:** `frontend/src/store/userPreferencesStore.ts`
- **Added:**
- `treeLibraryView`: 'grid' | 'list' | 'table' (default: 'grid')
- `treeLibrarySortBy`: Sort option type (default: 'usage_count')
- `setTreeLibraryView()` and `setTreeLibrarySortBy()` actions
- Persisted to localStorage via zustand middleware
#### 2. TypeScript Types
- **File:** `frontend/src/types/tree.ts`
- **Updated:** `TreeFilters` interface to include optional `sort_by` parameter
#### 3. New Components Created
**ViewToggle.tsx**
- Toggle buttons for Grid/List/Table views
- Visual icons from lucide-react
- Compact design with active state highlighting
**SortDropdown.tsx**
- Dropdown selector for 6 sort options
- Clean labels: "Most Used", "Recently Updated", etc.
- Responsive: hides label text on mobile
**TreeGridView.tsx**
- Extracted from original TreeLibraryPage
- Card-based layout (2-3 columns responsive)
- Shows: name, description, category, tags, version, usage, actions
- Includes delete button (admin only)
- Hover effects and smooth transitions
**TreeListView.tsx**
- Compact row-based view
- Single line per tree with truncated text
- Shows: name, description, category badge, tags (max 2), metadata
- Horizontal layout optimized for scanning
- Responsive: hides tags/metadata on smaller screens
**TreeTableView.tsx**
- Full-featured sortable table
- Columns: Name, Description, Category, Tags, Version, Uses, Updated, Actions
- Clickable column headers for in-table sorting
- Sort indicators (chevron up/down)
- Responsive column hiding (mobile → desktop)
- Fixed header with scrollable body
- Date formatting for "Updated" column
#### 4. Updated TreeLibraryPage
- **File:** `frontend/src/pages/TreeLibraryPage.tsx`
- **Changes:**
- Imports new components
- Adds view controls toolbar (sort dropdown + view toggle)
- Conditionally renders Grid/List/Table based on user preference
- Passes `sort_by` parameter to API
- Re-fetches data when sort preference changes
- Clean separation of concerns
### UI/UX Features
#### View Modes
1. **Grid View** (Default)
- Best for discovery and browsing
- Large cards with preview information
- 2-3 column responsive layout
- Hover animations
2. **List View**
- Best for quick scanning
- Compact rows with essential info
- Faster navigation
- More trees visible at once
3. **Table View**
- Best for power users and sorting
- Sortable columns
- Maximum information density
- Ideal for comparison
#### Sorting Options
- **Most Used** - Default, sorts by usage_count DESC
- **Recently Updated** - Newest updates first
- **Recently Created** - Newest trees first
- **Name (A-Z)** - Alphabetical ascending
- **Name (Z-A)** - Alphabetical descending
- **Version Number** - Highest version first
#### Responsive Design
- **Mobile:** Grid and List views only (table too complex)
- **Tablet:** All three views available
- **Desktop:** All views with optimal column widths
- View toggle and sort dropdown adapt to screen size
#### Persistence
- View preference saved to localStorage
- Sort preference saved to localStorage
- Preferences restored on page reload
- Per-user settings (no backend storage)
## Testing
### Backend Tests
```bash
cd backend
pytest tests/test_trees.py -v
# Result: 13/13 tests passed ✅
```
### Frontend Build
```bash
cd frontend
npm run build
# Result: Build successful ✅
# No TypeScript errors
# Bundle size: 731.24 kB (gzipped: 214.15 kB)
```
### Manual Testing Checklist
- [x] View toggle switches between Grid/List/Table
- [x] Sort dropdown updates tree order
- [x] Preferences persist across page reloads
- [x] All existing filters work with new views
- [x] Search functionality works with all views
- [x] Responsive design works on mobile/tablet/desktop
- [x] Table column sorting works
- [x] Edit/Delete/Start actions work in all views
- [x] Folder and tag filtering compatible
## Performance
- View switching: Instant (no API call, just re-render)
- Sort change: Single API request with new params
- No layout shift when switching views
- Smooth transitions and hover effects
- Lazy rendering for large tree lists
## Files Modified
### Backend (2 files)
- `backend/app/api/endpoints/trees.py` - Added sort_by parameter
- `backend/tests/test_trees.py` - Added sorting test
### Frontend (8 files)
- `frontend/src/store/userPreferencesStore.ts` - Added view/sort state
- `frontend/src/types/tree.ts` - Updated TreeFilters type
- `frontend/src/pages/TreeLibraryPage.tsx` - Integrated new views
- `frontend/src/components/library/ViewToggle.tsx` - NEW
- `frontend/src/components/library/SortDropdown.tsx` - NEW
- `frontend/src/components/library/TreeGridView.tsx` - NEW
- `frontend/src/components/library/TreeListView.tsx` - NEW
- `frontend/src/components/library/TreeTableView.tsx` - NEW
### Documentation (1 file)
- `IMPLEMENTATION-SUMMARY-ISSUE-34.md` - This file
## Breaking Changes
None. All changes are backward compatible:
- API defaults to existing behavior (usage_count sort)
- Frontend defaults to existing Grid view
- Existing filters and search continue to work
## Future Enhancements
Potential improvements for future iterations:
1. Save view preferences to backend (user profile)
2. Custom column selection for Table view
3. Export current view as CSV/JSON
4. Saved filter presets
5. Bulk actions in Table view
6. Drag-and-drop reordering in List view
7. Density controls (compact/comfortable/spacious)
## Acceptance Criteria
✅ Users can toggle between grid/list/table views
✅ Sort dropdown changes order dynamically
✅ View preference persists across sessions
✅ All views responsive on mobile/tablet/desktop
✅ Table view columns are sortable by clicking headers
✅ Performance: View switching <100ms, no layout shift
✅ Maintains existing functionality (search, filters, folders)
✅ Uses toast notifications for errors
✅ Clean, production-ready code with TypeScript types
✅ Comprehensive test coverage
## Next Steps
1. Merge to main branch
2. Deploy to Railway production
3. Monitor user feedback
4. Consider adding user preference sync to backend (future)
---
**Implementation by:** Claude Sonnet 4.5
**Review Status:** Ready for review
**Test Status:** All tests passing ✅

View File

@@ -0,0 +1,85 @@
# Notes/Thoughts/Ideas
This file is ignored by Claude (see .clauignore).
Use this for personal thoughts, todos, and reminders.
## 📝 Quick Thoughts
- Read CLAUDE.md and CURRENT-STATE.md before starting work on [your task].
- Update CURRENT-STATE.md with what was completed and update CLAUDE.md if we encountered any new issues.
-
## ✅ Personal TODO
- [ ] Answer the 5 key questions in docs/05-QUESTIONS-AND-ACTION-ITEMS.md
- [ ] Decide on app name (TroubleTree? DecisionPath? MSP Navigator?)
- [ ] Set up Render account for free tier testing
- [ ] Add patherly.com to my namecheap account for dynamic dns
## 💡 Feature Ideas (Future)
- Voice-guided troubleshooting for hands-free operation
- Integration with Teams/Slack for notifications
- AI suggestions based on past sessions
- Mobile app for on-site work
- Make an import plan function. Something where it can be written in text or formatted in such a way, and then imported as a plan.
## 🐛 Bugs to Track
- Sessions are not picking up where they left off. You get put back to the beginning of the tree you're working on.
## 🎯 This Week's Focus
**Goal:**
**Tasks:**
-
## 💬 Questions for the Team
-
-
## 📊 Metrics to Watch
- How many tickets am I using this on?
- Time saved per ticket?
- Are exports actually useful?
## 🔧 Technical Debt
-
## 🎨 Design Ideas
**1. Custom note formatting**
- Add a feature that allows the formatting of the ticket notes when they've been finished. For instance, if we have a 'send notes as email' feature, it would be a good idea to allow the customization of the ticket notes to include the ticket number, the client, the engineer who worked on it, and any other fields that are chosen to be added to the notes template.
**2. Options on the go**
- I think another valuable idea would be to allow users to select a troubleshooting step while in the midst of their tree. For instance, if they're in the middle of troubleshooting and they decide to try something outside of the current available options, allow them to select a pre-made troubleshooting technique and then take them to a point in the tree that makes sense. If more context is needed, I can provide it when we decide to work on this.
-
## 💰 Budget Tracking
**Current Hosting Cost:** $0 (Render free tier)
**Expected Cost in Production:** ~$25-35/month (Railway Pro)
## 📅 Timeline Tracking
**Week 1:** Project planning ✅
**Week 2:** Backend development
**Week 3:** Frontend + testing
**Week 4:** Deploy and dogfood
## 🎓 Things I'm Learning
-
-
## 🔗 Useful Links
- Render Dashboard: https://dashboard.render.com
- Railway Dashboard: https://railway.app
- Project Repo: [add when created]
---

View File

@@ -0,0 +1,727 @@
# Phase 2.5: Personal Tree Branching & Step Library
> **Status:** Planned (to begin after Phase 2 completion)
> **Timeline:** Weeks 7-8
> **Dependencies:** Phase 2 Tree Editor, Session History, User Permissions
---
## Overview
This feature allows users to customize their troubleshooting experience without modifying official trees. Users can add custom steps during active sessions, save modified trees as personal versions, and pull reusable steps from a shared library.
**Key Principle:** Non-destructive customization. Original trees remain untouched while users build personalized workflows.
---
## Feature Specification
### 10. Personal Tree Branching
**Description:** Allow users to insert custom steps during an active troubleshooting session, then optionally save the modified tree as their own version.
**User Flow:**
1. User navigates an official tree
2. At any decision point, clicks "+ Add Custom Step"
3. Chooses to type a custom step OR select from Step Library
4. Custom step is inserted into their session only
5. Session continues with custom step included
6. Export includes all custom steps with clear marking
7. After session, user is prompted to save as personal tree (optional)
**UI Components:**
- **Add Custom Step Button:** Appears at each decision node
- **Step Creation Modal:**
- Tab 1: "Type My Own" - free-form step creation
- Tab 2: "Browse Library" - searchable step repository
- **Custom Step Indicator:** Visual badge showing step is user-added
- **Save as Tree Prompt:** Post-session dialog to save modifications
**Custom Step Creation Form:**
```
┌─────────────────────────────────────────────────────────────┐
│ ADD CUSTOM STEP [X Close]│
├─────────────────────────────────────────────────────────────┤
│ [Type My Own] [Browse Library] │
├─────────────────────────────────────────────────────────────┤
│ │
│ Step Type: ○ Decision (Yes/No question) │
│ ○ Action (Task to perform) │
│ ○ Resolution (Issue resolved) │
│ │
│ Title/Question: ________________________________________ │
│ │
│ Help Text (optional): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Commands/Scripts (optional): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Get-Service BrokerAgent | Restart-Service │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ □ Save to My Step Library for reuse │
│ │
│ [Cancel] [Insert Step] │
└─────────────────────────────────────────────────────────────┘
```
**Technical Requirements:**
- Custom steps stored separately from original tree structure
- Session tracks insertion points (after which node)
- Export template handles custom step rendering
- Tree fork creates deep copy with user as owner
- Forked trees maintain reference to original (for analytics)
**Edge Cases:**
- Original tree updated after fork → Notify user, offer to merge changes
- User deletes custom step mid-session → Remove from session, continue
- Circular reference from custom step → Validate before insertion
- Custom step at terminal node → Allow, becomes new branch
---
### 11. Step Library
**Description:** A repository of reusable troubleshooting steps that users can pull into any session, organized by visibility, categories, tags, and user ratings.
**Library Hierarchy:**
```
Step Library
├── My Steps (private to user)
├── Team Steps (visible to team members)
├── Admin Curated (org-wide, managed by admins)
└── Community Steps (public, user-contributed, rated by users)
```
**Features:**
- **Search & Filter:**
- Full-text search across titles, descriptions, commands
- Filter by step type (decision, action, resolution)
- Filter by category (admin-managed)
- Filter by tags (user-defined)
- Filter by visibility level
- Filter by minimum rating (e.g., 4+ stars)
- Sort by: recent, popular, highest rated, most used
- **Step Preview:**
- View full step details before inserting
- See usage count and rating breakdown
- View author, creation date, and last updated
- See category and tags
- **Step Management:**
- Create new steps (saved to "My Steps")
- Assign category and add tags during creation
- Edit own steps
- Delete own steps
- Promote to Team (if permitted)
- Submit to Community (requires approval)
- **Admin Controls:**
- Approve/reject community submissions
- Curate "Admin Curated" collection
- Manage categories (create, rename, archive)
- Set default visibility for new steps
- Moderate inappropriate content
---
#### Categories (Admin-Managed)
Categories provide structured organization for steps. Admins define and manage categories to ensure consistency.
**Default Categories:**
| Category | Description |
|----------|-------------|
| Citrix / VDI | Virtual desktop, XenApp, XenDesktop, VDA issues |
| Active Directory | AD, LDAP, Group Policy, authentication |
| Microsoft 365 | Exchange Online, Teams, SharePoint, OneDrive |
| Networking | DNS, DHCP, VPN, firewall, connectivity |
| File Services | File shares, permissions, DFS, storage |
| Printing | Print servers, drivers, spooler issues |
| Backup & Recovery | Backup software, disaster recovery, restore |
| Security | Antivirus, permissions, security incidents |
| Hardware | Servers, workstations, peripherals |
| Other | Miscellaneous steps |
**Category Management (Admin UI):**
```
┌─────────────────────────────────────────────────────────────┐
│ MANAGE CATEGORIES [+ Add] │
├─────────────────────────────────────────────────────────────┤
│ Category │ Steps │ Status │ Actions │
├───────────────────────┼───────┼──────────┼─────────────────┤
│ Citrix / VDI │ 24 │ Active │ [Edit] [Archive]│
│ Active Directory │ 18 │ Active │ [Edit] [Archive]│
│ Microsoft 365 │ 31 │ Active │ [Edit] [Archive]│
│ Networking │ 15 │ Active │ [Edit] [Archive]│
│ Legacy Systems │ 3 │ Archived │ [Restore] │
└─────────────────────────────────────────────────────────────┘
```
---
#### Tags (User-Defined)
Tags provide flexible, user-driven organization. Users can create and apply tags freely.
**Tag Characteristics:**
- Created by any user when adding/editing a step
- Lowercase, alphanumeric with hyphens (e.g., `vda-registration`, `powershell`)
- Auto-suggest existing tags while typing
- Popular tags shown as quick-filters
- No limit on tags per step (recommended: 3-5)
**Popular Tags Example:**
`powershell` `quick-fix` `restart-service` `diagnostic` `permissions` `dns` `vpn` `cache-clear` `registry` `group-policy`
---
#### User Ratings & Reviews
Public and team steps can be rated by users to help surface the most helpful content.
**Rating System:**
- **Star Rating:** 1-5 stars (required when rating)
- **Helpful Vote:** Quick "Was this helpful?" Yes/No after using a step
- **Written Review:** Optional text feedback (max 500 chars)
- **One rating per user per step** (can update rating later)
**Rating Display:**
```
⭐⭐⭐⭐⭐ 4.7 (128 ratings)
├── 5 stars: ████████████████░░░░ 78%
├── 4 stars: ████░░░░░░░░░░░░░░░░ 15%
├── 3 stars: █░░░░░░░░░░░░░░░░░░░ 4%
├── 2 stars: ░░░░░░░░░░░░░░░░░░░░ 2%
└── 1 star: ░░░░░░░░░░░░░░░░░░░░ 1%
👍 94% found this helpful (156 votes)
```
**Review Display:**
```
┌─────────────────────────────────────────────────────────────┐
│ ⭐⭐⭐⭐⭐ "Saved me hours of troubleshooting!" │
│ @SarahM • Jan 20, 2026 • Verified Use │
├─────────────────────────────────────────────────────────────┤
│ ⭐⭐⭐⭐☆ "Good step, but needed to modify for our env" │
│ @TechJohn • Jan 18, 2026 • Verified Use │
└─────────────────────────────────────────────────────────────┘
```
**Rating Rules:**
- Only users who have actually used the step can rate it ("Verified Use" badge)
- Step author cannot rate their own step
- Ratings update the step's average in real-time
- Steps with <5 ratings show "Not enough ratings" instead of average
- Admin can remove abusive reviews
---
**Step Library Browser UI:**
```
┌─────────────────────────────────────────────────────────────┐
│ STEP LIBRARY [X Close]│
├─────────────────────────────────────────────────────────────┤
│ Search: [_________________________] [🔍] │
│ │
│ Category: [All Categories ▼] Type: [All Types ▼] │
│ Source: [All Sources ▼] Min Rating: [Any ▼] │
│ │
│ Popular Tags: [powershell] [quick-fix] [diagnostic] [dns] │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─ MY STEPS (3) ──────────────────────────────────────────┐│
│ │ ⚡ Check Event Viewer for Citrix Errors ││
│ │ Action • Citrix / VDI • Used 12 times ││
│ │ Tags: citrix, event-viewer, vda ││
│ │ [Insert] ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ ┌─ TEAM STEPS (12) ───────────────────────────────────────┐│
│ │ ⚡ Clear Teams Cache ││
│ │ Action • Microsoft 365 • By Sarah M. ││
│ │ ⭐ 4.8 (23 ratings) • 👍 96% helpful ││
│ │ Tags: teams, cache-clear, quick-fix ││
│ │ [Insert] ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ ┌─ COMMUNITY (47) ────────────────────────────────────────┐│
│ │ ⚡ Reset Windows Update Components ││
│ │ Action • Security • By @yourMSP ││
│ │ ⭐ 4.9 (1.2k ratings) • 👍 98% helpful • 🔥 Popular ││
│ │ Tags: windows-update, powershell, fix ││
│ │ [Preview] [Insert]││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ [+ Create New Step] │
└─────────────────────────────────────────────────────────────┘
```
**Step Detail / Preview Modal:**
```
┌─────────────────────────────────────────────────────────────┐
│ STEP DETAILS [X Close]│
├─────────────────────────────────────────────────────────────┤
│ ⚡ Reset Windows Update Components │
│ │
│ Category: Security │
│ Tags: [windows-update] [powershell] [fix] [troubleshooting] │
│ │
│ ⭐⭐⭐⭐⭐ 4.9 (1,247 ratings) • 👍 98% found helpful │
│ Used 3,842 times • By @yourMSP • Created Nov 12, 2025 │
├─────────────────────────────────────────────────────────────┤
│ INSTRUCTIONS: │
│ This script stops Windows Update services, clears the │
│ download cache, and restarts the services. │
│ │
│ COMMANDS: │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ # Run as Administrator ││
│ │ Stop-Service wuauserv, bits, cryptsvc -Force ││
│ │ Remove-Item $env:systemroot\SoftwareDistribution -Rec.. ││
│ │ Start-Service wuauserv, bits, cryptsvc ││
│ └─────────────────────────────────────────────────────────┘│
│ [📋 Copy] │
│ │
│ HELP TEXT: │
│ Run this when Windows Update is stuck or showing errors. │
│ May require a reboot after running. │
├─────────────────────────────────────────────────────────────┤
│ TOP REVIEWS: │
│ ⭐⭐⭐⭐⭐ "Fixed a month-long update issue!" - @ITpro │
│ ⭐⭐⭐⭐☆ "Works great, added a reboot step" - @helpdesk │
│ [See all 89 reviews] │
├─────────────────────────────────────────────────────────────┤
│ [Cancel] [Insert Into Session]│
└─────────────────────────────────────────────────────────────┘
```
---
**Data Structure:**
```json
{
"step_id": "step_abc123",
"title": "Check Event Viewer for Citrix Errors",
"step_type": "action",
"content": {
"instructions": "Open Event Viewer and navigate to Applications and Services Logs > Citrix",
"help_text": "Look for errors in the last 30 minutes that coincide with the reported issue time",
"commands": [
{
"label": "Open Event Viewer",
"command": "eventvwr.msc",
"type": "run"
},
{
"label": "PowerShell - Get Citrix Errors",
"command": "Get-WinEvent -LogName 'Citrix-*' -MaxEvents 50 | Where-Object {$_.LevelDisplayName -eq 'Error'}",
"type": "powershell"
}
],
"documentation_links": [
{
"title": "Citrix Event Log Reference",
"url": "https://docs.citrix.com/...",
"type": "vendor_docs"
}
]
},
"organization": {
"category_id": "cat_citrix_vdi",
"category_name": "Citrix / VDI",
"tags": ["citrix", "event-viewer", "vda", "diagnostics"]
},
"ratings": {
"average": 4.7,
"count": 128,
"distribution": {
"5": 100,
"4": 19,
"3": 5,
"2": 3,
"1": 1
},
"helpful_yes": 147,
"helpful_no": 9,
"helpful_percentage": 94
},
"metadata": {
"created_by": "user_123",
"author_display_name": "@MichaelC",
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-01-20T14:15:00Z",
"visibility": "public",
"team_id": null,
"usage_count": 342,
"is_featured": false,
"is_verified": true
}
}
```
---
### 12. Personal Tree Management
**Description:** Users can save, organize, and share their customized tree versions.
**Features:**
- **My Trees Dashboard:**
- List of user's forked/custom trees
- Original tree reference (if forked)
- Last used date
- Quick actions (edit, share, delete)
- **Tree Forking:**
- Fork from any tree user has access to
- Fork from another user's shared tree (fork of fork)
- Maintain lineage tracking
- **Sharing Options:**
- Private (only me)
- Share via link (anyone with link)
- Share with team
- Make public (community)
- **Version Awareness:**
- Notification when original tree is updated
- Diff view showing changes
- Option to merge updates into fork
- Option to ignore updates
**My Trees UI:**
```
┌─────────────────────────────────────────────────────────────┐
│ MY CUSTOM TREES [+ Create New] │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ 🌲 Citrix VDA - Warner Robins Specific ││
│ │ Forked from: Citrix VDA Not Registering (Official) ││
│ │ Modified: 3 custom steps added ││
│ │ Last used: 2 days ago • Used 8 times ││
│ │ Sharing: 🔒 Private ││
│ │ ││
│ │ [▶ Start Session] [✏️ Edit] [🔗 Share] [🗑️] ││
│ │ ││
│ │ ⚠️ Original tree updated 1 day ago [View Changes] ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ 🌲 Quick Office 365 License Check ││
│ │ Original creation (not a fork) ││
│ │ Last used: 1 week ago • Used 3 times ││
│ │ Sharing: 👥 Team ││
│ │ ││
│ │ [▶ Start Session] [✏️ Edit] [🔗 Share] [🗑️] ││
│ └─────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────┘
```
**Share Modal:**
```
┌─────────────────────────────────────────────────────────────┐
│ SHARE TREE [X Close]│
├─────────────────────────────────────────────────────────────┤
│ │
│ "Citrix VDA - Warner Robins Specific" │
│ │
│ Who can access this tree? │
│ │
│ ○ 🔒 Private - Only me │
│ ○ 🔗 Anyone with link - No login required │
│ ○ 👥 My Team - All team members can use │
│ ○ 🌍 Public - Submit to community library │
│ │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ 🔗 https://patherly.app/tree/abc123xyz ││
│ │ [📋 Copy] ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ □ Allow others to fork this tree │
│ □ Show my name as author │
│ │
│ [Cancel] [Save Sharing] │
└─────────────────────────────────────────────────────────────┘
```
---
## Database Schema Additions
### New Tables
```sql
-- Step categories (admin-managed)
CREATE TABLE step_categories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL UNIQUE,
description TEXT,
display_order INTEGER DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Seed default categories
INSERT INTO step_categories (name, description, display_order) VALUES
('Citrix / VDI', 'Virtual desktop, XenApp, XenDesktop, VDA issues', 1),
('Active Directory', 'AD, LDAP, Group Policy, authentication', 2),
('Microsoft 365', 'Exchange Online, Teams, SharePoint, OneDrive', 3),
('Networking', 'DNS, DHCP, VPN, firewall, connectivity', 4),
('File Services', 'File shares, permissions, DFS, storage', 5),
('Printing', 'Print servers, drivers, spooler issues', 6),
('Backup & Recovery', 'Backup software, disaster recovery, restore', 7),
('Security', 'Antivirus, permissions, security incidents', 8),
('Hardware', 'Servers, workstations, peripherals', 9),
('Other', 'Miscellaneous steps', 100);
-- Reusable step library
CREATE TABLE step_library (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
step_type VARCHAR(50) NOT NULL CHECK (step_type IN ('decision', 'action', 'resolution')),
content JSONB NOT NULL,
-- Ownership
created_by UUID NOT NULL REFERENCES users(id),
team_id UUID REFERENCES teams(id),
-- Organization
category_id UUID REFERENCES step_categories(id),
tags VARCHAR(100)[] DEFAULT '{}',
-- Visibility: 'private', 'team', 'org', 'public'
visibility VARCHAR(50) NOT NULL DEFAULT 'private',
-- Aggregated ratings (updated by trigger or application)
usage_count INTEGER DEFAULT 0,
rating_average DECIMAL(3,2) DEFAULT 0,
rating_count INTEGER DEFAULT 0,
helpful_yes INTEGER DEFAULT 0,
helpful_no INTEGER DEFAULT 0,
-- Flags
is_featured BOOLEAN DEFAULT FALSE,
is_verified BOOLEAN DEFAULT FALSE,
-- Timestamps
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- Soft delete
is_active BOOLEAN DEFAULT TRUE
);
-- User's forked/custom trees
CREATE TABLE user_trees (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Ownership
user_id UUID NOT NULL REFERENCES users(id),
-- Fork tracking (null if original creation)
forked_from_tree_id UUID REFERENCES trees(id),
forked_from_user_tree_id UUID REFERENCES user_trees(id),
forked_at_version INTEGER, -- Version of original when forked
-- Tree content
name VARCHAR(255) NOT NULL,
description TEXT,
category VARCHAR(100),
tree_content JSONB NOT NULL, -- Full tree structure
-- Sharing: 'private', 'link', 'team', 'public'
visibility VARCHAR(50) NOT NULL DEFAULT 'private',
share_token VARCHAR(100) UNIQUE, -- For link sharing
allow_forking BOOLEAN DEFAULT TRUE,
show_author BOOLEAN DEFAULT TRUE,
-- Stats
usage_count INTEGER DEFAULT 0,
fork_count INTEGER DEFAULT 0,
-- Timestamps
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
-- Soft delete
is_active BOOLEAN DEFAULT TRUE
);
-- Custom steps added during sessions
CREATE TABLE session_custom_steps (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
-- Insertion point
inserted_after_node_id VARCHAR(100) NOT NULL,
position_order INTEGER NOT NULL, -- For multiple custom steps at same point
-- Step content (either from library or custom)
step_library_id UUID REFERENCES step_library(id),
custom_content JSONB, -- Used if not from library
-- Timestamps
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
CONSTRAINT step_source_check CHECK (
(step_library_id IS NOT NULL AND custom_content IS NULL) OR
(step_library_id IS NULL AND custom_content IS NOT NULL)
)
);
-- Step ratings and reviews
CREATE TABLE step_ratings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
step_id UUID NOT NULL REFERENCES step_library(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id),
-- Star rating (1-5, required)
rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
-- Helpful vote (optional, set after using step)
was_helpful BOOLEAN,
-- Written review (optional)
review_text VARCHAR(500),
-- Verification
is_verified_use BOOLEAN DEFAULT FALSE, -- Set true when user actually used this step in a session
session_id UUID REFERENCES sessions(id), -- Link to session where step was used
-- Moderation
is_visible BOOLEAN DEFAULT TRUE, -- Admin can hide abusive reviews
-- Timestamps
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(step_id, user_id)
);
-- Track step usage for "Verified Use" badge
CREATE TABLE step_usage_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
step_id UUID NOT NULL REFERENCES step_library(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id),
session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
used_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Indexes for performance
CREATE INDEX idx_step_library_visibility ON step_library(visibility) WHERE is_active = TRUE;
CREATE INDEX idx_step_library_team ON step_library(team_id) WHERE is_active = TRUE;
CREATE INDEX idx_step_library_created_by ON step_library(created_by) WHERE is_active = TRUE;
CREATE INDEX idx_step_library_tags ON step_library USING GIN(tags);
CREATE INDEX idx_step_library_search ON step_library USING GIN(to_tsvector('english', title || ' ' || COALESCE(content->>'instructions', '')));
CREATE INDEX idx_user_trees_user ON user_trees(user_id) WHERE is_active = TRUE;
CREATE INDEX idx_user_trees_visibility ON user_trees(visibility) WHERE is_active = TRUE;
CREATE INDEX idx_user_trees_share_token ON user_trees(share_token) WHERE share_token IS NOT NULL;
CREATE INDEX idx_session_custom_steps_session ON session_custom_steps(session_id);
CREATE INDEX idx_step_categories_active ON step_categories(is_active, display_order);
CREATE INDEX idx_step_ratings_step ON step_ratings(step_id) WHERE is_visible = TRUE;
CREATE INDEX idx_step_ratings_user ON step_ratings(user_id);
CREATE INDEX idx_step_usage_log_step ON step_usage_log(step_id);
CREATE INDEX idx_step_usage_log_user_step ON step_usage_log(user_id, step_id);
```
---
## API Endpoints
### Step Categories
```
GET /api/v1/categories # List active categories
POST /api/v1/categories # Create category (admin only)
PUT /api/v1/categories/{id} # Update category (admin only)
DELETE /api/v1/categories/{id} # Archive category (admin only)
```
### Step Library
```
GET /api/v1/steps # List steps (filtered by visibility, category, tags, rating)
GET /api/v1/steps/{id} # Get step details with ratings
POST /api/v1/steps # Create new step
PUT /api/v1/steps/{id} # Update step
DELETE /api/v1/steps/{id} # Delete step (soft)
GET /api/v1/steps/search?q= # Search steps (full-text)
GET /api/v1/steps/tags/popular # Get popular tags
```
### Step Ratings & Reviews
```
GET /api/v1/steps/{id}/reviews # Get reviews for a step
POST /api/v1/steps/{id}/rate # Rate a step (star rating + optional review)
PUT /api/v1/steps/{id}/rate # Update your rating
DELETE /api/v1/steps/{id}/rate # Remove your rating
POST /api/v1/steps/{id}/helpful # Vote helpful (yes/no)
DELETE /api/v1/reviews/{id} # Hide review (admin only)
```
### User Trees
```
GET /api/v1/user-trees # List user's custom trees
GET /api/v1/user-trees/{id} # Get custom tree
POST /api/v1/user-trees # Create new custom tree
POST /api/v1/user-trees/fork/{tree_id}# Fork an official tree
PUT /api/v1/user-trees/{id} # Update custom tree
DELETE /api/v1/user-trees/{id} # Delete custom tree (soft)
PUT /api/v1/user-trees/{id}/share # Update sharing settings
GET /api/v1/shared/{share_token} # Access shared tree (no auth required)
```
### Session Custom Steps
```
POST /api/v1/sessions/{id}/custom-steps # Add custom step to session
DELETE /api/v1/sessions/{id}/custom-steps/{step_id} # Remove custom step
POST /api/v1/sessions/{id}/save-as-tree # Save session as custom tree
```
---
## Integration with Existing Features
| Existing Feature | Integration Point |
|------------------|-------------------|
| Tree Navigation | Add "+ Custom Step" button at each node |
| Session Tracking | Track custom steps in session data |
| Export | Include custom steps with visual distinction |
| Tree Editor | Use same node editor for custom step creation |
| Search | Include user trees and step library in search |
| Analytics | Track custom step usage, popular forks |
| Permissions | Respect team/org visibility settings |
---
## Success Criteria
- [ ] Users can add custom steps during any session
- [ ] Custom steps appear correctly in exports
- [ ] Step library search returns relevant results in <500ms
- [ ] Users can fork trees and save modifications
- [ ] Sharing via link works without login (if configured)
- [ ] Team steps are visible to all team members
- [ ] Original tree owners can see fork count
- [ ] No data leakage between visibility levels
---
## Future Enhancements (Phase 4+)
- **Step Suggestions:** AI suggests relevant steps based on current context
- **Merge Tool:** Visual diff/merge when original tree updates
- **Step Analytics:** Which custom steps get promoted to official trees
- **Community Voting:** Upvote/downvote community contributions
- **Step Templates:** Pre-built step structures for common patterns
- **Import/Export:** Share steps via JSON file

View File

@@ -0,0 +1,785 @@
# 🎨 ResolutionFlow Brand Rebuild - Implementation Guide
## 📋 Pre-Implementation Checklist
**Before starting, complete these safety steps:**
```powershell
cd C:\Dev\Projects\patherly
git add .
git commit -m "Pre-rebrand checkpoint - Patherly working state"
git checkout -b rebrand-to-resolutionflow
```
**Copy brand assets:**
- Place all 8 SVG files in: `C:\Dev\Projects\patherly\brand-assets\`
---
## 🎯 Project Context
**Current State:**
- React + TypeScript + Tailwind CSS project
- Location: `C:\Dev\Projects\patherly\frontend\`
- Using shadcn/ui components
- "Patherly" hardcoded in AppLayout.tsx and LoginPage.tsx
- Default shadcn color scheme (not branded)
- No custom logo/favicon
**Target State:**
- Complete ResolutionFlow branding
- Purple gradient theme (#818cf8#a78bfa)
- Dark mode optimized
- Custom fonts (Plus Jakarta Sans, Inter, Outfit)
- Professional logo in header and favicon
---
## 📦 PHASE 1: Asset Deployment
### 1.1 Create Asset Directories
```bash
mkdir -p frontend/public/icons
mkdir -p frontend/src/assets/brand
```
### 1.2 Copy Brand Assets
Copy files from `C:\Dev\Projects\patherly\brand-assets\` to:
| Source File | Destination |
|------------|-------------|
| `favicon.svg` | `frontend/public/icons/favicon.svg` |
| `icon.svg` | `frontend/public/icons/icon.svg` |
| `app-icon-gradient.svg` | `frontend/public/icons/app-icon-gradient.svg` |
| `logo-horizontal.svg` | `frontend/src/assets/brand/logo-horizontal.svg` |
| `logo-with-tagline.svg` | `frontend/src/assets/brand/logo-with-tagline.svg` |
| `icon.svg` | `frontend/src/assets/brand/icon.svg` |
### 1.3 Update index.html
**File:** `frontend/index.html`
Replace the entire `<head>` section with:
```html
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/icons/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ResolutionFlow - Decision Tree Platform</title>
<meta name="description" content="Transform troubleshooting into guided workflows with automatic documentation" />
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Inter:wght@400;500;600&family=Outfit:wght@400;500;600;700&display=swap" rel="stylesheet">
<!-- PWA Icons -->
<link rel="apple-touch-icon" href="/icons/app-icon-gradient.svg" />
<meta name="theme-color" content="#09090b" />
<script>
// Prevent flash of wrong theme on initial load
(function() {
try {
const stored = JSON.parse(localStorage.getItem('theme-storage') || '{}');
const theme = stored.state?.theme || 'system';
const isDark = theme === 'dark' ||
(theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
if (isDark) document.documentElement.classList.add('dark');
} catch (e) {}
})();
</script>
</head>
```
---
## 🎨 PHASE 2: Tailwind Theme Configuration
### 2.1 Update Tailwind Config
**File:** `frontend/tailwind.config.js`
Replace the entire file with:
```javascript
/** @type {import('tailwindcss').Config} */
export default {
darkMode: ["class"],
content: [
"./index.html",
"./src/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
// ResolutionFlow Brand Colors
brand: {
gradient: {
from: '#818cf8',
to: '#a78bfa',
},
dark: {
DEFAULT: '#09090b',
card: '#18181b',
surface: '#12121c',
},
text: {
primary: '#ffffff',
secondary: '#a1a1aa',
muted: '#52525b',
},
border: '#27272a',
},
// shadcn/ui color system
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
fontFamily: {
sans: ['Inter', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
heading: ['Plus Jakarta Sans', 'system-ui', 'sans-serif'],
label: ['Outfit', 'system-ui', 'sans-serif'],
},
backgroundImage: {
'gradient-brand': 'linear-gradient(90deg, #818cf8 0%, #a78bfa 100%)',
'gradient-brand-hover': 'linear-gradient(90deg, #6366f1 0%, #9333ea 100%)',
},
},
},
plugins: [],
}
```
---
## 🎨 PHASE 3: Global Styles
### 3.1 Update Global CSS
**File:** `frontend/src/index.css`
Replace the entire file with:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
/* Light mode (fallback) */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 243 75% 59%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 243 75% 59%;
--radius: 0.75rem;
}
.dark {
/* ResolutionFlow Dark Theme */
--background: 240 10% 3.9%;
--foreground: 0 0% 100%;
--card: 240 10% 9.4%;
--card-foreground: 0 0% 100%;
--popover: 240 10% 9.4%;
--popover-foreground: 0 0% 100%;
--primary: 243 75% 59%;
--primary-foreground: 0 0% 100%;
--secondary: 240 5.9% 15%;
--secondary-foreground: 0 0% 100%;
--muted: 240 5.9% 15%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 5.9% 15%;
--accent-foreground: 0 0% 100%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 100%;
--border: 240 5.9% 15%;
--input: 240 5.9% 15%;
--ring: 243 75% 59%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
font-weight: 700;
letter-spacing: -0.02em;
}
}
@layer utilities {
.text-gradient-brand {
@apply bg-gradient-brand bg-clip-text text-transparent;
}
}
```
---
## 🔧 PHASE 4: Component Updates
### 4.1 Update AppLayout Component
**File:** `frontend/src/components/layout/AppLayout.tsx`
Replace the entire file with:
```typescript
import { Link, useLocation, useNavigate, Outlet } from 'react-router-dom'
import { useAuthStore } from '@/store/authStore'
import { ThemeToggle } from '@/components/common/ThemeToggle'
import { cn } from '@/lib/utils'
export function AppLayout() {
const location = useLocation()
const navigate = useNavigate()
const { user, logout } = useAuthStore()
const handleLogout = async () => {
await logout()
navigate('/login')
}
const navItems = [
{ path: '/trees', label: 'Trees' },
{ path: '/sessions', label: 'Sessions' },
{ path: '/settings', label: 'Settings' },
]
return (
<div className="min-h-screen bg-background">
{/* Header */}
<header className="sticky top-0 z-50 border-b border-border bg-card backdrop-blur-sm">
<div className="container mx-auto flex h-16 items-center justify-between px-4">
<div className="flex items-center gap-8">
<Link to="/trees" className="flex items-center gap-2">
{/* Logo */}
<svg viewBox="0 0 40 40" fill="none" className="h-8 w-8">
<defs>
<linearGradient id="logo-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="#818cf8"/>
<stop offset="100%" stopColor="#a78bfa"/>
</linearGradient>
</defs>
<circle cx="5" cy="7" r="2.5" fill="url(#logo-grad)" opacity="0.35"/>
<circle cx="5" cy="15" r="2.75" fill="url(#logo-grad)" opacity="0.5"/>
<circle cx="5" cy="25" r="2.75" fill="url(#logo-grad)" opacity="0.5"/>
<circle cx="5" cy="33" r="2.5" fill="url(#logo-grad)" opacity="0.35"/>
<path d="M7.5 7L14 17" stroke="url(#logo-grad)" strokeWidth="1" strokeLinecap="round" strokeDasharray="1 1.5" opacity="0.45"/>
<path d="M7.75 15L14 19" stroke="url(#logo-grad)" strokeWidth="1" strokeLinecap="round" opacity="0.6"/>
<path d="M7.75 25L14 21" stroke="url(#logo-grad)" strokeWidth="1" strokeLinecap="round" opacity="0.6"/>
<path d="M7.5 33L14 23" stroke="url(#logo-grad)" strokeWidth="1" strokeLinecap="round" strokeDasharray="1 1.5" opacity="0.45"/>
<circle cx="18" cy="20" r="5" fill="url(#logo-grad)" opacity="0.15"/>
<circle cx="18" cy="20" r="3.5" fill="url(#logo-grad)"/>
<path d="M21.5 20H35M35 20L30 15M35 20L30 25" stroke="url(#logo-grad)" strokeWidth="1.25" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
{/* Wordmark */}
<span className="font-heading text-xl font-bold">
<span className="text-foreground">Resolution</span>
<span className="text-gradient-brand">Flow</span>
</span>
</Link>
<nav className="hidden items-center gap-1 sm:flex">
{navItems.map((item) => (
<Link
key={item.path}
to={item.path}
className={cn(
'rounded-md px-3 py-2 text-sm font-medium transition-colors',
location.pathname.startsWith(item.path)
? 'bg-accent text-accent-foreground'
: 'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
)}
>
{item.label}
</Link>
))}
</nav>
</div>
<div className="flex items-center gap-4">
<span className="hidden text-sm text-muted-foreground sm:block">
{user?.name || user?.email}
</span>
<ThemeToggle />
<button
onClick={handleLogout}
className={cn(
'rounded-md px-3 py-1.5 text-sm font-medium',
'text-muted-foreground hover:bg-accent hover:text-accent-foreground'
)}
>
Logout
</button>
</div>
</div>
</header>
{/* Main Content */}
<main>
<Outlet />
</main>
</div>
)
}
export default AppLayout
```
### 4.2 Update LoginPage Component
**File:** `frontend/src/pages/LoginPage.tsx`
Replace the entire file with:
```typescript
import { useState } from 'react'
import { Link, useNavigate, useLocation } from 'react-router-dom'
import { useAuthStore } from '@/store/authStore'
import { cn } from '@/lib/utils'
export function LoginPage() {
const navigate = useNavigate()
const location = useLocation()
const { login, isLoading, error, clearError } = useAuthStore()
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [localError, setLocalError] = useState('')
const from = (location.state as { from?: { pathname: string } })?.from?.pathname || '/trees'
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
setLocalError('')
clearError()
if (!email || !password) {
setLocalError('Please enter both email and password')
return
}
try {
await login({ email, password })
navigate(from, { replace: true })
} catch {
// Error is set in the store
}
}
return (
<div className="flex min-h-screen items-center justify-center bg-background px-4">
<div className="w-full max-w-md space-y-8">
{/* Header with Logo */}
<div className="text-center">
<div className="mb-6 flex justify-center">
<svg viewBox="0 0 80 80" fill="none" className="h-20 w-20">
<defs>
<linearGradient id="login-logo-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="#818cf8"/>
<stop offset="100%" stopColor="#a78bfa"/>
</linearGradient>
</defs>
<circle cx="10" cy="14" r="5" fill="url(#login-logo-grad)" opacity="0.35"/>
<circle cx="10" cy="30" r="5.5" fill="url(#login-logo-grad)" opacity="0.5"/>
<circle cx="10" cy="50" r="5.5" fill="url(#login-logo-grad)" opacity="0.5"/>
<circle cx="10" cy="66" r="5" fill="url(#login-logo-grad)" opacity="0.35"/>
<path d="M15 14L28 34" stroke="url(#login-logo-grad)" strokeWidth="2" strokeLinecap="round" strokeDasharray="2 3" opacity="0.45"/>
<path d="M15.5 30L28 38" stroke="url(#login-logo-grad)" strokeWidth="2" strokeLinecap="round" opacity="0.6"/>
<path d="M15.5 50L28 42" stroke="url(#login-logo-grad)" strokeWidth="2" strokeLinecap="round" opacity="0.6"/>
<path d="M15 66L28 46" stroke="url(#login-logo-grad)" strokeWidth="2" strokeLinecap="round" strokeDasharray="2 3" opacity="0.45"/>
<circle cx="36" cy="40" r="10" fill="url(#login-logo-grad)" opacity="0.15"/>
<circle cx="36" cy="40" r="7" fill="url(#login-logo-grad)"/>
<path d="M43 40H70M70 40L60 30M70 40L60 50" stroke="url(#login-logo-grad)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</div>
<h1 className="font-heading text-3xl font-bold tracking-tight">
<span className="text-foreground">Resolution</span>
<span className="text-gradient-brand">Flow</span>
</h1>
<p className="mt-3 text-lg text-gradient-brand font-medium">
Decision Tree Platform
</p>
<p className="mt-2 text-sm text-muted-foreground">
Sign in to your account
</p>
</div>
<form onSubmit={handleSubmit} className="mt-8 space-y-6">
<div className="space-y-4 rounded-lg border border-border bg-card p-6 shadow-lg">
{(error || localError) && (
<div className="rounded-md bg-destructive/10 p-3 text-sm text-destructive border border-destructive/20">
{localError || error}
</div>
)}
<div>
<label htmlFor="email" className="block text-sm font-medium text-foreground mb-1">
Email address
</label>
<input
id="email"
name="email"
type="email"
autoComplete="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
className={cn(
'block w-full rounded-md border border-input bg-background px-3 py-2',
'text-foreground placeholder:text-muted-foreground',
'focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20',
'transition-colors'
)}
placeholder="you@example.com"
/>
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium text-foreground mb-1">
Password
</label>
<input
id="password"
name="password"
type="password"
autoComplete="current-password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
className={cn(
'block w-full rounded-md border border-input bg-background px-3 py-2',
'text-foreground placeholder:text-muted-foreground',
'focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20',
'transition-colors'
)}
placeholder="••••••••••"
/>
</div>
<button
type="submit"
disabled={isLoading}
className={cn(
'w-full rounded-md px-4 py-2.5 text-sm font-semibold text-white',
'bg-gradient-brand hover:bg-gradient-brand-hover',
'focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50',
'transition-all shadow-lg shadow-primary/20'
)}
>
{isLoading ? 'Signing in...' : 'Sign in'}
</button>
</div>
<p className="text-center text-sm text-muted-foreground">
Don't have an account?{' '}
<Link
to="/register"
className="font-medium text-gradient-brand hover:underline"
>
Register
</Link>
</p>
</form>
</div>
</div>
)
}
export default LoginPage
```
### 4.3 Update RegisterPage Component
**File:** `frontend/src/pages/RegisterPage.tsx`
**Changes needed:**
1. Add the logo SVG before the title (same as LoginPage)
2. Update title to match ResolutionFlow branding
3. Update submit button to use gradient styling
**Find this section:**
```typescript
<div className="text-center">
<h1 className="text-3xl font-bold tracking-tight text-foreground">Patherly</h1>
<p className="mt-2 text-muted-foreground">Create your account</p>
</div>
```
**Replace with:**
```typescript
<div className="text-center">
<div className="mb-6 flex justify-center">
<svg viewBox="0 0 80 80" fill="none" className="h-20 w-20">
<defs>
<linearGradient id="register-logo-grad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="#818cf8"/>
<stop offset="100%" stopColor="#a78bfa"/>
</linearGradient>
</defs>
<circle cx="10" cy="14" r="5" fill="url(#register-logo-grad)" opacity="0.35"/>
<circle cx="10" cy="30" r="5.5" fill="url(#register-logo-grad)" opacity="0.5"/>
<circle cx="10" cy="50" r="5.5" fill="url(#register-logo-grad)" opacity="0.5"/>
<circle cx="10" cy="66" r="5" fill="url(#register-logo-grad)" opacity="0.35"/>
<path d="M15 14L28 34" stroke="url(#register-logo-grad)" strokeWidth="2" strokeLinecap="round" strokeDasharray="2 3" opacity="0.45"/>
<path d="M15.5 30L28 38" stroke="url(#register-logo-grad)" strokeWidth="2" strokeLinecap="round" opacity="0.6"/>
<path d="M15.5 50L28 42" stroke="url(#register-logo-grad)" strokeWidth="2" strokeLinecap="round" opacity="0.6"/>
<path d="M15 66L28 46" stroke="url(#register-logo-grad)" strokeWidth="2" strokeLinecap="round" strokeDasharray="2 3" opacity="0.45"/>
<circle cx="36" cy="40" r="10" fill="url(#register-logo-grad)" opacity="0.15"/>
<circle cx="36" cy="40" r="7" fill="url(#register-logo-grad)"/>
<path d="M43 40H70M70 40L60 30M70 40L60 50" stroke="url(#register-logo-grad)" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</div>
<h1 className="font-heading text-3xl font-bold tracking-tight">
<span className="text-foreground">Resolution</span>
<span className="text-gradient-brand">Flow</span>
</h1>
<p className="mt-3 text-lg text-gradient-brand font-medium">
Decision Tree Platform
</p>
<p className="mt-2 text-sm text-muted-foreground">
Create your account
</p>
</div>
```
**Find the submit button:**
```typescript
<button
type="submit"
disabled={isLoading}
className={cn(
'w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground',
// ... rest of classes
)}
>
```
**Replace with:**
```typescript
<button
type="submit"
disabled={isLoading}
className={cn(
'w-full rounded-md px-4 py-2.5 text-sm font-semibold text-white',
'bg-gradient-brand hover:bg-gradient-brand-hover',
'focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2',
'disabled:cursor-not-allowed disabled:opacity-50',
'transition-all shadow-lg shadow-primary/20'
)}
>
```
---
## 🔍 PHASE 5: Search and Replace
Search for any remaining "Patherly" references in the codebase:
**Command to find references:**
```powershell
cd frontend/src
Select-String -Path . -Pattern "Patherly" -Recurse
```
**Replace all instances with "ResolutionFlow"**
Common places to check:
- Page titles
- Comments
- Error messages
- API descriptions
- Console logs
---
## ✅ PHASE 6: Verification Checklist
### 6.1 Start Development Server
```bash
cd frontend
npm run dev
```
### 6.2 Visual Checks
- [ ] **Login Page**
- Logo displays correctly
- ResolutionFlow branding visible
- Purple gradient on submit button
- Fonts loaded (Plus Jakarta Sans for title)
- [ ] **Register Page**
- Matches login page styling
- Logo and branding consistent
- [ ] **App Header**
- Logo in navbar
- "ResolutionFlow" wordmark (Resolution + Flow gradient)
- Navigation items styled correctly
- [ ] **Browser Tab**
- New favicon visible
- Title shows "ResolutionFlow"
- [ ] **Theme Toggle**
- Dark mode works
- Colors look correct in both modes
- Purple gradients visible
- [ ] **Console**
- No errors in browser console
- Fonts loading successfully
### 6.3 Functionality Checks
- [ ] Login works
- [ ] Registration works
- [ ] Navigation works
- [ ] Theme toggle works
- [ ] All existing features preserved
---
## 🎉 Success Criteria
✅ New ResolutionFlow logo in header
✅ Purple gradient theme throughout
✅ Custom fonts loaded (Plus Jakarta Sans, Inter, Outfit)
✅ No "Patherly" references remaining
✅ Favicon updated in browser tab
✅ Login/Register pages fully branded
✅ Dark mode optimized
✅ All existing functionality preserved
---
## 📝 Post-Implementation
### Commit Changes
```powershell
git add .
git commit -m "Complete rebrand to ResolutionFlow - new logo, colors, fonts, and branding"
git push origin rebrand-to-resolutionflow
```
### Create Pull Request
Review the changes and merge into main when ready.
---
## 🆘 Rollback Plan
If something goes wrong:
```powershell
git checkout main
git branch -D rebrand-to-resolutionflow
```
This will discard all changes and return to your pre-rebrand state.
---
## 📋 Known Issues & Solutions
### Issue: Fonts Not Loading
**Solution:** Clear browser cache and hard refresh (Ctrl+Shift+R)
### Issue: Logo Not Showing
**Solution:** Check that SVG files were copied to correct directories
### Issue: Gradient Not Visible
**Solution:** Verify Tailwind config was updated and dev server was restarted
### Issue: Dark Mode Colors Wrong
**Solution:** Check that index.css was fully replaced with new CSS variables
---
## 🔗 Reference Files
- Brand Guide: `brand-assets/brand-guide.html`
- App Mockups: `brand-assets/app-mockups.html`
- Original Assets: `brand-assets/*.svg`
---
**Last Updated:** February 2026
**Version:** 1.0
**Status:** Ready for Implementation

783
docs/archive/TS-EXAMPLES.md Normal file
View File

@@ -0,0 +1,783 @@
# Troubleshooting Scenarios for Decision Tree App
## Scenario 1: FSLogix Profile Not Loading
### Issue Details
**Issue Name:** FSLogix Profile Not Loading
**Category:** Citrix/Virtual Desktop
**Estimated Time:** 10-15 minutes
**Common For:** Warner Robins City, other Citrix environments
### First Thing You Check
Can the user log into the server at all?
### Decision Tree
**Step 1: Can user log into server?**
- **YES** → Step 2: Check FSLogix service status
- **NO** → Different tree (AD account/licensing issue)
**Step 2: Is FSLogix service running on the server?**
- **RUNNING** → Step 3: Check frxtray.exe in user's task manager
- **STOPPED** → Step 4: Start service and check event log for cause
- **STUCK (Starting/Stopping)** → Step 5: Kill service process and restart
**Step 3: Is frxtray.exe running in user's task manager?**
- **YES** → Step 6: Check if profile VHD exists in share
- **NO** → Step 7: Check FSLogix agent installation
- **MULTIPLE INSTANCES** → Step 8: Kill all frxtray.exe, log user off, try again
**Step 4: Service Start Result**
*Action: Start-Service -Name 'frxsvc'*
- **Started successfully** → Step 9: Check Event Viewer for previous failure reason
- **Failed to start** → Step 10: Check service dependencies (NetLogon, RPC)
- **Started but stopped again** → Step 11: Check for file locks or permissions
**Step 5: Service Kill and Restart**
*Action: Stop-Process -Name frxsvc -Force; Start-Service frxsvc*
- **Service now running** → Step 3: Verify frxtray.exe
- **Still stuck** → Step 12: Check for corrupt profile or registry
**Step 6: Does user have a profile VHD in the share?**
*Check: \\server\fslogix\username\Profile_username.vhdx*
- **YES, file exists** → Step 13: Check VHD file permissions
- **NO, file missing** → Step 14: Check FSLogix registry path configuration
- **YES, but 0 bytes** → Step 15: Delete corrupt VHD, recreate profile
**Step 7: Is FSLogix agent installed?**
*Check: C:\Program Files\FSLogix\Apps\frxsvc.exe exists*
- **YES** → Step 16: Repair FSLogix agent
- **NO** → Step 17: Install FSLogix agent
**Step 8: Multiple frxtray instances**
*Action: Get-Process frxtray | Stop-Process -Force*
- **Killed successfully** → Log user off, have them log back in
- **Cannot kill** → Step 18: Check for file/folder locks
**Step 9: Check Event Viewer**
*Action: Check Application log for FSLogix errors*
- **Error 50 (Can't access network path)** → Step 19: Verify network path accessible
- **Error 13 (VHD locked)** → Step 20: Check for locks on VHD from other servers
- **Error 52 (Profile path not found)** → Step 14: Check registry settings
**Step 10: Check Service Dependencies**
*Action: Get-Service NetLogon, RpcSs status*
- **All running** → Step 21: Check antivirus blocking
- **NetLogon stopped** → Start NetLogon, then retry FSLogix
- **RPC stopped** → Critical issue, escalate to senior engineer
**Step 11: Check for File Locks**
*Action: Run Chihlas file lock checker on profile share*
- **No locks** → Step 22: Check disk space on profile server
- **Locked by another server** → Step 20: Release lock or force user logoff from other session
**Step 13: Check VHD Permissions**
*Action: Get-Acl on Profile_username.vhdx*
- **User has Full Control** → Step 23: Try mounting VHD manually
- **User missing permissions** → Step 24: Grant user full control
- **Everyone has permission but still fails** → Step 25: Check parent folder permissions
**Step 14: Check FSLogix Registry Path**
*Check: HKLM\SOFTWARE\FSLogix\Profiles - VHDLocations*
- **Path is correct** → Step 26: Check DNS resolution of server name
- **Path has typo** → Fix registry path, log user off and back on
- **Path uses old server** → Update to correct server path
**Step 15: Delete Corrupt VHD**
*Action: Delete 0-byte VHD file*
- **Deleted successfully** → User will get new profile on next login
- **Cannot delete (in use)** → Step 20: Check locks, force release
**Step 17: Install FSLogix Agent**
*Action: Run FSLogix installer from network share*
- **Installed successfully** → Reboot server, have user try again
- **Installation failed** → Step 27: Check server OS version compatibility
**Step 19: Verify Network Path**
*Action: Test-Path \\server\fslogix from problem server*
- **Accessible** → Step 28: Check firewall between servers
- **Not accessible** → Check DNS, check network connectivity
- **Accessible but slow** → Step 29: Check network performance
**Step 20: Check VHD Locks**
*Action: Use openfiles /query or handle.exe to check locks*
- **Locked by same server** → Kill locking process
- **Locked by different server** → Log user off from that server
- **Lock from crashed session** → Clear stale session, release lock
**Step 21: Check Antivirus**
*Action: Check if AV is scanning/blocking FSLogix folders*
- **FSLogix folders excluded** → Step 30: Check Windows Defender exclusions too
- **Not excluded** → Add exclusions, restart FSLogix service
- **Exclusions present but still blocking** → Temporarily disable AV to test
**Step 23: Try Mounting VHD Manually**
*Action: Mount-VHD -Path \\server\fslogix\...\Profile.vhdx*
- **Mounts successfully** → Profile is good, issue elsewhere (back to Step 2)
- **Fails to mount** → Step 31: Check VHD integrity
- **Mounts but takes forever** → Step 29: Network performance issue
**Step 24: Grant User Permissions**
*Action: icacls add full control for user on VHD*
- **Permissions granted** → Have user log off and back on
- **Cannot modify permissions** → Check if admin has access, check share permissions
**Step 31: Check VHD Integrity**
*Action: Test-VHD -Path ... in PowerShell*
- **VHD is healthy** → Issue is mounting or permissions
- **VHD is corrupt** → Step 15: Delete and recreate
- **Cannot test (access denied)** → Permission issue on share
**RESOLUTION: Profile loads successfully**
### Common Pitfalls
- VHD file locked by another server (user has session on multiple servers)
- Profile path in registry has typo or uses old server name
- Antivirus blocking VHD access or scanning profile folder
- NetLogon service stopped preventing network authentication
- Disk full on profile share
- DNS not resolving profile server name
- Stale sessions from crashed RDP connections
### Resolution Indicators
- User can log in successfully
- Profile loads within 30 seconds
- No FSLogix errors in Event Viewer
- frxtray.exe running in task manager
- User's desktop, documents appear correctly
### Documentation Links
- FSLogix Profile Troubleshooting: https://docs.microsoft.com/en-us/fslogix/troubleshooting-profile-container
- Event Log Error Codes: https://docs.microsoft.com/en-us/fslogix/profile-container-configuration-reference
- VHD Troubleshooting: Internal KB #FSL-001
---
## Scenario 2: Citrix VDA Not Registering
### Issue Details
**Issue Name:** Citrix VDA Not Registering with Delivery Controller
**Category:** Citrix/Virtual Desktop
**Estimated Time:** 10-20 minutes
**Common For:** Warner Robins City, all Citrix environments
### First Thing You Check
Can you ping the VDA from the Delivery Controller?
### Decision Tree
**Step 1: Can you ping VDA from DDC?**
*Action: Test-Connection -ComputerName VDA-HOSTNAME*
- **YES (replies)** → Step 2: Check VDA service status
- **NO (request timed out)** → Step 3: Network connectivity issue
**Step 2: What is VDA service status?**
*Action: Get-Service -Name 'BrokerAgent' on VDA*
- **RUNNING** → Step 4: Check DDC connection from VDA
- **STOPPED** → Step 5: Start VDA service
- **STUCK** → Step 6: Force kill and restart service
**Step 3: Network Connectivity Issue**
*Troubleshooting network layer*
- **VDA powered off** → Power on VDA, wait for boot
- **VDA on different subnet** → Step 7: Check routing/firewall
- **DNS not resolving** → Step 8: Check DNS configuration
- **Network cable unplugged** → Physical layer issue
**Step 4: Can VDA reach DDC on port 80/443?**
*Action: Test-NetConnection -ComputerName DDC-HOSTNAME -Port 80*
- **Port 80 success** → Step 9: Check VDA registration in Studio
- **Port 80 blocked** → Step 10: Check firewall rules
- **DNS fails** → Step 8: Check DNS
**Step 5: Start VDA Service**
*Action: Start-Service -Name 'BrokerAgent'*
- **Started successfully** → Step 11: Wait 60 seconds, check registration
- **Failed to start** → Step 12: Check Event Viewer for error
- **Started then stopped** → Step 13: Check service dependencies
**Step 6: Force Kill VDA Service**
*Action: Stop-Process -Name BrokerAgent -Force*
- **Killed successfully** → Step 5: Start service normally
- **Cannot kill (access denied)** → Restart VDA server
- **Killed but immediately respawns** → Step 14: Check for loops
**Step 7: Check Routing/Firewall**
*Between VDA and DDC*
- **Different VLANs** → Verify inter-VLAN routing configured
- **SonicWall between them** → Step 15: Check SonicWall rules
- **Switches involved** → Check VLAN tagging, trunk ports
**Step 8: Check DNS Configuration**
*Action: Resolve-DnsName DDC-HOSTNAME from VDA*
- **Resolves correctly** → DNS is fine, go back to network troubleshooting
- **Does not resolve** → Step 16: Check VDA DNS server settings
- **Resolves to wrong IP** → Step 17: Check DNS A record
**Step 9: Check VDA in Citrix Studio**
*Action: Open Studio > Machine Catalogs*
- **VDA shows "Registered"** → Issue resolved!
- **VDA shows "Unregistered"** → Step 18: Check ListOfDDCs registry
- **VDA not in catalog** → Step 19: Add VDA to catalog
**Step 10: Check Firewall Rules**
*Between VDA and DDC*
- **Windows Firewall blocking** → Create rule to allow DDC traffic
- **Hardware firewall blocking** → Step 15: Update SonicWall rules
- **NSG rules (if Azure)** → Add allow rule for ports 80, 443, 1494, 2598
**Step 11: Wait and Verify Registration**
*Action: Wait 60 seconds, refresh Studio*
- **Now registered** → Resolution confirmed!
- **Still unregistered** → Step 18: Check ListOfDDCs
- **Shows error in Studio** → Step 20: Check specific error code
**Step 12: Check Event Viewer**
*Action: Application log, filter for Citrix*
- **Error 1001 (cannot contact DDC)** → Step 4: Check connectivity
- **Error 1006 (auth failure)** → Step 21: Check machine account
- **Error 1035 (database connection failed)** → Escalate to DDC troubleshooting
**Step 13: Check Service Dependencies**
*Action: Check dependent services*
- **NetLogon stopped** → Start NetLogon first
- **Remote Registry stopped** → Start Remote Registry
- **Windows Event Log stopped** → Critical, may need reboot
**Step 15: Check SonicWall Rules**
*Between VDA subnet and DDC subnet*
- **No rule exists** → Create LAN→LAN allow rule for Citrix ports
- **Rule exists but wrong ports** → Add ports 80, 443, 1494, 2598
- **Rule exists, looks correct** → Check packet capture on SonicWall
**Step 16: Check VDA DNS Settings**
*Action: Get-DnsClientServerAddress on VDA*
- **Points to wrong DNS** → Set to correct DNS server
- **Points to correct DNS** → Step 17: Check DNS server itself
- **No DNS configured** → Configure DNS, restart VDA
**Step 17: Check DNS A Record**
*On DNS server*
- **A record correct** → Clear DNS cache on VDA
- **A record wrong IP** → Update A record, clear cache
- **A record missing** → Create A record for DDC
**Step 18: Check ListOfDDCs Registry**
*Action: Check HKLM\Software\Citrix\VirtualDesktopAgent - ListOfDDCs*
- **Points to correct DDC** → Step 22: Re-register VDA manually
- **Points to old/wrong DDC** → Update registry to correct DDC name
- **Registry key missing** → Run Citrix VDA installer repair
**Step 19: Add VDA to Catalog**
*In Citrix Studio*
- **Added successfully** → VDA should register within 60 seconds
- **Cannot add (not found)** → Step 1: Network connectivity issue
- **Cannot add (duplicate)** → VDA may be in different catalog, search
**Step 21: Check Machine Account**
*In Active Directory*
- **Account exists, enabled** → Step 23: Check computer trust relationship
- **Account disabled** → Enable account, restart VDA
- **Account missing** → Re-join VDA to domain
**Step 22: Re-register VDA Manually**
*Action: Run "C:\Program Files\Citrix\Virtual Desktop Agent\BrokerAgent.exe" -RegisterWithDDC*
- **Registration successful** → Verify in Studio
- **Registration failed** → Check error message, return to Step 4
- **Command not found** → VDA install corrupted, reinstall
**Step 23: Check Computer Trust Relationship**
*Action: Test-ComputerSecureChannel on VDA*
- **Trust relationship good** → Back to Step 2
- **Trust relationship broken** → Repair: Reset-ComputerMachinePassword
- **Repair failed** → Re-join domain
**RESOLUTION: VDA shows as Registered in Studio**
### Common Pitfalls
- Firewall blocking ports 80/443 between VDA and DDC
- DNS not resolving DDC hostname
- ListOfDDCs registry points to old/decommissioned DDC
- Machine account password expired or trust relationship broken
- VDA service won't stay running due to corrupt installation
- Network routing issue between VDA and DDC subnets
- VDA trying to register to wrong DDC in multi-site setup
### Resolution Indicators
- VDA shows "Registered" in Citrix Studio
- Users can successfully launch sessions to VDA
- No Citrix errors in Event Viewer
- VDA appears in correct delivery group
### Documentation Links
- VDA Registration: https://docs.citrix.com/en-us/citrix-virtual-apps-desktops/manage-deployment/vda-registration
- Troubleshooting: https://support.citrix.com/article/CTX136668
- Event Log Errors: https://support.citrix.com/article/CTX127348
---
## Scenario 3: User Cannot Access File Share
### Issue Details
**Issue Name:** User Cannot Access Network File Share
**Category:** File Services / Permissions
**Estimated Time:** 5-15 minutes
**Common For:** All clients with file servers
### First Thing You Check
Can the user ping the file server?
### Decision Tree
**Step 1: Can user ping file server by name?**
*Action: ping FILE-SERVER-NAME*
- **YES (replies)** → Step 2: Can user access share path
- **NO (timeout/host unreachable)** → Step 3: Network connectivity issue
- **Unknown host** → Step 4: DNS resolution issue
**Step 2: Can user access \\server\share in File Explorer?**
*Action: Navigate to \\SERVER\SHARE*
- **YES, opens** → Step 5: Check specific folder permissions
- **NO, access denied** → Step 6: Check share permissions
- **NO, network path not found** → Step 7: Check SMB service
**Step 3: Network Connectivity Issue**
*Troubleshooting layer 3*
- **User on VPN** → Step 8: Check VPN tunnel status
- **User on different site** → Step 9: Check site-to-site connectivity
- **Server on different VLAN** → Check inter-VLAN routing
- **Cable unplugged** → Physical issue
**Step 4: DNS Resolution Issue**
*Action: nslookup FILE-SERVER-NAME*
- **Resolves to correct IP** → Try accessing by IP: \\192.168.1.10\share
- **Does not resolve** → Step 10: Check DNS configuration
- **Resolves to wrong IP** → Step 11: Update DNS record
**Step 5: Can user access specific folder?**
*Action: Open \\server\share\specific-folder*
- **YES** → Issue resolved!
- **NO, access denied** → Step 12: Check NTFS permissions on folder
- **Folder doesn't exist** → Verify correct path, check if moved
**Step 6: Check Share Permissions**
*Action: Right-click share > Properties > Sharing > Permissions*
- **User has Read or Change** → Step 12: Check NTFS permissions
- **User not in permissions** → Step 13: Add user to share permissions
- **Everyone has Full Control** → Share perms OK, issue is NTFS
**Step 7: Check SMB Service**
*Action: Get-Service -Name LanmanServer on file server*
- **Running** → Step 14: Check SMB signing requirements
- **Stopped** → Start service, verify user can access
- **Disabled** → Enable and start service
**Step 8: Check VPN Tunnel**
*If user is remote*
- **VPN connected** → Step 15: Check VPN routing for file server subnet
- **VPN disconnected** → Reconnect VPN, retry
- **VPN connected but can't reach internal** → Step 16: Check split tunneling
**Step 9: Site-to-Site Connectivity**
*Between user's site and file server site*
- **Ping works between sites** → Not a site link issue
- **Ping fails between sites** → Step 17: Check VPN tunnel between sites
- **Some services work, files don't** → Check port 445 specifically
**Step 10: Check User's DNS Settings**
*Action: ipconfig /all on user's PC*
- **DNS points to DC** → Step 18: Check DNS server health
- **DNS points to wrong server** → Set correct DNS via DHCP or static
- **No DNS configured** → Configure DNS
**Step 12: Check NTFS Permissions**
*Action: Right-click folder > Properties > Security*
- **User has Read & Execute** → User should have access
- **User not listed** → Step 19: Check group memberships
- **User has Deny** → Step 20: Remove explicit Deny
**Step 13: Add User to Share Permissions**
*Action: Add user or user's group with appropriate access*
- **Added successfully** → User should now be able to access
- **Cannot add (grayed out)** → Check if Advanced Sharing is needed
- **Added but still fails** → Step 12: Check NTFS permissions
**Step 14: Check SMB Signing**
*Action: Check SMB server/client signing requirements*
- **Client requires signing, server doesn't** → Enable signing on server
- **Mismatch in SMB versions** → Step 21: Enable SMB 2.0/3.0
- **Settings match** → Not SMB signing issue
**Step 15: Check VPN Routing**
*Verify file server subnet is routed through VPN*
- **Route exists** → Check firewall rules on VPN
- **Route missing** → Add route for file server subnet
- **Route exists but traffic blocked** → Step 22: Check firewall
**Step 17: Check Site-to-Site VPN**
*Between locations*
- **Tunnel up** → Step 23: Check Phase 2 includes port 445
- **Tunnel down** → Troubleshoot VPN (separate tree)
- **Tunnel flapping** → Check for routing loops
**Step 18: Check DNS Server**
*On domain controller/DNS server*
- **DNS service running** → Check if A record exists for file server
- **DNS service stopped** → Start DNS service
- **High CPU/memory** → May need DNS server restart
**Step 19: Check Group Memberships**
*Action: Check what groups user belongs to*
- **User in correct group** → Step 24: Run gpupdate to refresh token
- **User not in group** → Add user to appropriate group
- **User added recently** → User needs to log off and back on
**Step 20: Remove Explicit Deny**
*Deny permissions override all allows*
- **Deny removed** → User should now have access
- **Deny is inherited** → Step 25: Check parent folder permissions
- **Cannot remove (grayed out)** → Disable inheritance, then remove
**Step 21: Enable SMB 2.0/3.0**
*Action: Enable SMB versions on server*
- **Enabled successfully** → User should now connect
- **Already enabled** → Check Windows version compatibility
- **Cannot enable** → OS version too old, may need upgrade
**Step 24: Refresh User Token**
*Action: Have user log off and back on (or run klist purge)*
- **After logoff/logon, works** → Resolution confirmed
- **Still fails after logoff** → Step 26: Check effective permissions
**Step 26: Check Effective Permissions**
*Action: Advanced Security > Effective Access*
- **Shows user should have access** → Step 27: Check for inheritance issues
- **Shows user has no access** → Permission configuration error
- **Tool shows access but user still can't** → Clear SMB cache
**RESOLUTION: User can access share and specific folders**
### Common Pitfalls
- User has NTFS permissions but not share permissions (or vice versa)
- User added to group but hasn't logged off/on to refresh token
- Explicit Deny permission overriding Allow permissions
- DNS not resolving file server name
- Firewall blocking port 445 (SMB)
- DFS namespace issues (different issue, separate tree)
- Offline Files caching causing stale view
### Resolution Indicators
- User can open \\server\share
- User can create/modify files if they should have write access
- File Explorer shows correct folders
- No "Access Denied" or "Network Path Not Found" errors
### Documentation Links
- SMB Troubleshooting: https://docs.microsoft.com/en-us/windows-server/storage/file-server/troubleshoot/
- File Permissions: Internal KB #NTFS-PERMS-001
- DFS Issues: Internal KB #DFS-TROUBLESHOOT
---
## Scenario 4: Active Directory Replication Failure
### Issue Details
**Issue Name:** Active Directory Replication Not Working
**Category:** Active Directory / Infrastructure
**Estimated Time:** 15-30 minutes
**Common For:** Multi-DC environments, especially after DC issues
### First Thing You Check
Can the DCs ping each other?
### Decision Tree
**Step 1: Can DCs ping each other by name?**
*Action: Test-Connection between all DCs*
- **YES, all reply** → Step 2: Check replication status
- **NO, some don't reply** → Step 3: Network connectivity issue
- **Name doesn't resolve** → Step 4: DNS issue
**Step 2: What does replicadmin /showrepl show?**
*Action: repadmin /showrepl on each DC*
- **Last replication: recent (< 1 hour)** → Replication working
- **Last replication: old (> 3 hours)** → Step 5: Check for specific errors
- **Replication failing with error** → Step 6: Identify error code
**Step 3: Network Connectivity Between DCs**
*Layer 3 troubleshooting*
- **Different sites** → Step 7: Check site link configuration
- **Firewall between DCs** → Step 8: Check firewall rules
- **Same site but can't reach** → Check switches, VLANs
**Step 4: DNS Issues Between DCs**
*Action: nslookup DC-NAME from other DC*
- **Resolves correctly** → Not DNS issue, back to Step 1
- **Doesn't resolve** → Step 9: Check DNS zone replication
- **Resolves to wrong IP** → Step 10: Update DNS A record
**Step 5: Check for Specific Replication Errors**
*Review repadmin output*
- **"Last attempt was successful"** → False alarm, replication OK
- **Shows specific error code** → Step 6: Identify error code
- **No errors but time is old** → Step 11: Force replication
**Step 6: Identify Replication Error Code**
*Common error codes*
- **Error 8606 (insufficient attributes)** → Step 12: Metadata cleanup needed
- **Error 8451/8452 (naming context)** → Step 13: Name server not advertising
- **Error 1722 (RPC server unavailable)** → Step 14: RPC/firewall issue
- **Error 1256 (domain trust issue)** → Step 15: Secure channel problem
- **Error 8614 (version mismatch)** → Step 16: Schema version issue
**Step 7: Check Site Link Configuration**
*Action: Check AD Sites and Services*
- **Site link exists** → Step 17: Check site link schedule
- **No site link** → Create site link between sites
- **Link cost too high** → Adjust link cost if needed
**Step 8: Check Firewall Rules Between DCs**
*Required ports for AD replication*
- **Ports 135, 389, 636, 3268, 49152+ open** → Not firewall issue
- **Some ports blocked** → Step 18: Open required AD ports
- **All ports open but still fails** → Back to Step 6 for errors
**Step 9: Check DNS Zone Replication**
*Action: Check _msdcs zone on both DCs*
- **Zone present on both** → Step 19: Check SRV records
- **Zone missing on one DC** → Step 20: Force DNS zone replication
- **Zone present but not replicating** → Check DNS application partition
**Step 11: Force Replication**
*Action: repadmin /syncall /AdeP*
- **Replication succeeded** → Check if ongoing or one-time issue
- **Still failing** → Step 6: Check specific error
- **Partially succeeded** → Identify which DCs failing
**Step 12: Metadata Cleanup for Error 8606**
*Action: ntdsutil metadata cleanup*
- **Phantom DC found** → Remove phantom DC object
- **No phantoms** → Step 21: Check USN rollback
- **Cleanup completed** → Force replication, verify
**Step 13: Name Server Not Advertising (8451/8452)**
*DC not advertising itself properly*
- **netlogon service stopped** → Start netlogon service
- **netlogon running** → Step 22: Re-register netlogon DNS records
- **After reregister, still fails** → Check DNS zone for SRV records
**Step 14: RPC Server Unavailable (1722)**
*RPC connectivity issue*
- **Port 135 blocked** → Step 8: Open port 135
- **Port open but RPC fails** → Step 23: Check RPC service status
- **RPC service running** → Check endpoint mapper
**Step 15: Secure Channel Problem (1256)**
*Computer account trust issue*
- **Password mismatch** → Step 24: Reset computer account
- **Account locked** → Unlock computer account in AD
- **Account missing** → Serious issue, may need DC demotion/promotion
**Step 16: Schema Version Mismatch (8614)**
*Schema versions don't match*
- **One DC has older schema** → Step 25: Update schema on older DC
- **Schema versions match** → May be false positive, check metadata
**Step 17: Check Site Link Schedule**
*Action: Site link properties > Change Schedule*
- **Replication blocked in current time** → Wait or adjust schedule
- **Schedule allows replication** → Step 26: Check site link cost
- **Schedule set to never** → Configure proper schedule
**Step 18: Open Required AD Ports**
*On firewall between DCs*
- **Rules added** → Test replication after 5 minutes
- **Cannot add rules** → Escalate to network team
- **Rules exist but traffic blocked** → Check for other firewalls
**Step 19: Check SRV Records**
*Action: nslookup -type=SRV _ldap._tcp.dc._msdcs.DOMAIN*
- **Both DCs listed** → DNS is good
- **One DC missing** → Step 22: Re-register DNS
- **No DCs listed** → Critical DNS issue, Step 20
**Step 20: Force DNS Zone Replication**
*Action: repadmin /replicate for DNS partitions*
- **DNS replicated** → Verify SRV records now present
- **DNS replication failed** → Check for DNS-specific errors
- **Partial replication** → May need multiple attempts
**Step 22: Re-register Netlogon DNS Records**
*Action: nltest /dsregdns on problem DC*
- **Registration succeeded** → Check DNS for new SRV records
- **Registration failed** → Check DNS service, Event Viewer
- **Succeeded but records still missing** → Manual creation needed
**Step 23: Check RPC Service**
*Action: Get-Service RPCSS*
- **Running** → Step 27: Check RPC port range
- **Stopped** → Start RPCSS service (critical!)
- **Stuck starting** → Reboot DC (after-hours if possible)
**Step 24: Reset Computer Account**
*Action: Reset-ComputerMachinePassword -Server PDC*
- **Reset successful** → Force replication, verify
- **Reset failed** → May need to reset from authoritative DC
- **After reset, still fails** → Deeper trust issue, may need demotion
**Step 27: Check RPC Port Range**
*Action: Check dynamic port range*
- **Default range (49152-65535)** → Range is fine
- **Custom restricted range** → Step 28: Ensure both DCs use same range
- **No dynamic ports available** → Exhaustion issue, investigate
**RESOLUTION: repadmin /showrepl shows recent successful replication on all DCs**
### Common Pitfalls
- Firewall blocking high ports (49152+) needed for RPC
- DNS SRV records missing or incorrect
- Phantom domain controller objects in AD Sites and Services
- Secure channel broken between DCs
- Time skew between DCs (> 5 minutes causes Kerberos failures)
- Antivirus blocking AD replication traffic
- Incorrect site link configuration
### Resolution Indicators
- repadmin /showrepl shows successful replication within last hour
- No replication errors in Directory Services event log
- dcdiag /test:replications passes
- Changes propagate between DCs within expected timeframe
- No Event ID 2042 (too long since last replication)
### Documentation Links
- AD Replication: https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/manage/troubleshoot/
- Repadmin Guide: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc770963(v=ws.11)
- Error Codes: Internal KB #AD-REPL-ERRORS
---
## Scenario 5: Password Reset Request (Simple Example)
### Issue Details
**Issue Name:** User Forgot Password - Needs Reset
**Category:** Account Management
**Estimated Time:** 2-5 minutes
**Common For:** Daily helpdesk task
### First Thing You Check
Verify user's identity
### Decision Tree
**Step 1: Can you verify user's identity?**
*Check against company verification policy*
- **YES (verified via phone/email/manager)** → Step 2: Locate user account
- **NO (cannot verify)** → Deny request, inform user of verification process
- **User is contractor** → Step 3: Check if manager approval required
**Step 2: Can you find user account in AD?**
*Action: Search Active Directory for username*
- **Account found** → Step 4: Check account status
- **Account not found** → Step 5: Check if name spelled correctly
- **Multiple accounts** → Step 6: Identify correct account
**Step 3: Manager Approval for Contractor**
*Per company policy*
- **Manager approves** → Step 2: Proceed with reset
- **Manager denies** → Inform contractor, deny request
- **Cannot reach manager** → Escalate to IT manager
**Step 4: Is account enabled?**
*Check account status*
- **Enabled** → Step 7: Reset password
- **Disabled** → Step 8: Check why disabled
- **Locked out** → Step 9: Unlock and reset
**Step 5: Check Name Spelling**
*Verify with user*
- **Found with correct spelling** → Step 4: Check status
- **Still not found** → Check if account exists, may need creation
- **User doesn't have account** → Route to new user request process
**Step 6: Identify Correct Account**
*Multiple John Smiths, etc.*
- **Identified by employee ID** → Step 4: Proceed
- **Identified by department** → Step 4: Proceed
- **Cannot identify** → Ask user for more info (start date, manager, etc.)
**Step 7: Reset Password**
*Action: Set temporary password in AD*
- **Reset successful** → Step 10: Communicate new password to user
- **Cannot reset (permission denied)** → Escalate to higher-level admin
- **Reset but user still can't login** → Step 11: Check for other issues
**Step 8: Account Disabled - Check Why**
*Look at account notes or ticket history*
- **Disabled for termination** → Do not enable, inform requester
- **Disabled for inactivity** → Step 12: Verify if user still employed
- **Disabled in error** → Enable account and reset password
**Step 9: Unlock Account**
*Action: Unlock account in AD*
- **Unlocked successfully** → Step 7: Reset password
- **Unlock failed** → Wait 15 minutes (lockout duration), try again
- **Immediately locks again** → Step 13: Check for automated login attempts
**Step 10: Communicate New Password**
*Securely provide temp password*
- **Told user over phone** → Instruct user must change at login
- **Sent via secure portal** → Provide portal link
- **User received password** → Step 14: Verify user can login
**Step 11: Reset Success But Login Failed**
*After reset, user still can't login*
- **Wrong username** → Provide correct username
- **Caps Lock on** → Inform user
- **Password not synced yet** → Wait 2-3 minutes, retry
- **MFA issue** → Different troubleshooting path
**Step 12: Verify User Still Employed**
*Check with HR or manager*
- **Still employed** → Enable account, reset password
- **Terminated** → Do not enable, close ticket
- **Unknown status** → Escalate to IT manager
**Step 13: Check for Automated Login Attempts**
*Saved credentials somewhere*
- **Old laptop auto-logging** → Have user change password on laptop
- **Mobile device** → Remove saved password on phone
- **Service account** → Update service account password
- **Can't identify source** → Change password multiple times
**Step 14: Verify User Can Login**
*Confirm with user*
- **Login successful** → Step 15: Set user must change password
- **Still cannot login** → Return to Step 11
- **Login works but can't access email** → Different issue
**Step 15: Force Password Change at Next Login**
*If not already set*
- **User will be prompted** → Document ticket, close
- **User successfully changed** → Resolution confirmed!
- **User locked out again** → May be complexity requirement issue
**RESOLUTION: User successfully logged in with new password**
### Common Pitfalls
- Not verifying user identity properly
- Forgetting to check if account is locked (not just disabled)
- Not telling user to change password at next login
- Multiple accounts for same name, resetting wrong one
- Account syncs slowly to other systems (email, VPN, etc.)
- User typing username incorrectly after reset
### Resolution Indicators
- User confirms successful login
- Account shows last login timestamp updated
- No subsequent lockout or password reset requests
- User able to access all required systems
### Documentation Links
- Password Policy: Internal KB #PWD-POLICY
- Identity Verification: Internal KB #ID-VERIFY
- Account Management: Internal KB #AD-ACCOUNTS

View File

@@ -0,0 +1,608 @@
# Workspace Removal & Navigation Refactor — Implementation Plan
> **Purpose:** Combined implementation plan for removing the workspace system, renaming UI labels (Trees→Flows, Procedures→Projects), adding pinned flows, and restructuring sidebar navigation.
> **Source of Truth:** [UI-DESIGN-SYSTEM.md](UI-DESIGN-SYSTEM.md) v2
> **Date:** February 15, 2026
> **Tailwind Version:** v3 only — do not use v4 syntax or patterns (see `package.json` line 56)
---
## Why This Change
Workspaces added unnecessary cognitive overhead for the target MSP audience. UX research (Hick's Law, context-switching studies) shows that at the current product scale (10-15 beta testers, <50 flows per account), a workspace switcher creates friction without organizational benefit. The replacement is a flat navigation model with type sub-items and pinned favorites.
---
## Phase 1 — Backend: Add Pinned Flows (ship BEFORE removing workspaces)
> **Important sequencing:** Add the pinned flows feature first and verify it works. Then remove workspaces in Phase 2. This ensures the replacement feature is stable before tearing out the old one. If both are done in the same session, at minimum run the pinned flows tests before starting workspace removal.
### 1a. Add Pinned Flows Table
```bash
cd backend
alembic revision --autogenerate -m "add_user_pinned_trees"
```
```sql
CREATE TABLE user_pinned_trees (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
tree_id UUID NOT NULL REFERENCES trees(id) ON DELETE CASCADE,
display_order INTEGER NOT NULL DEFAULT 0,
pinned_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_user_pinned_tree UNIQUE (user_id, tree_id)
);
CREATE INDEX idx_user_pinned_trees_user ON user_pinned_trees(user_id);
CREATE INDEX idx_user_pinned_trees_tree ON user_pinned_trees(tree_id);
```
### 1b. Pinned Flows API Contract
**Endpoints:**
| Method | Path | Description | Auth |
|--------|------|-------------|------|
| `GET` | `/api/v1/trees/pinned` | List user's pinned flows (ordered by display_order) | Required |
| `POST` | `/api/v1/trees/{id}/pin` | Pin a flow to sidebar | Required |
| `DELETE` | `/api/v1/trees/{id}/pin` | Unpin a flow from sidebar | Required |
| `PATCH` | `/api/v1/trees/pinned/reorder` | Update display_order for all pinned flows | Required |
**Constraints & Limits:**
- Max 15 pinned flows per user (return 409 if exceeded)
- `UNIQUE(user_id, tree_id)` — pinning an already-pinned flow returns 200 (idempotent), not an error
- Unpinning an already-unpinned flow returns 200 (idempotent)
- When a tree is deleted, cascade removes the pin automatically (FK ON DELETE CASCADE)
- Pins are per-user, not per-account — each user has their own pinned set
**Response Shapes:**
```typescript
// GET /api/v1/trees/pinned
interface PinnedFlowsResponse {
items: PinnedFlow[];
count: number;
}
interface PinnedFlow {
id: string; // pin record id
tree_id: string;
tree_name: string;
tree_type: 'troubleshooting' | 'procedural';
category_emoji?: string;
category_name?: string;
pinned_at: string; // ISO datetime
display_order: number;
}
// POST /api/v1/trees/{id}/pin → returns PinnedFlow
// DELETE /api/v1/trees/{id}/pin → returns { success: true }
// PATCH /api/v1/trees/pinned/reorder
// body: { order: [{ tree_id: string, display_order: number }] }
// returns: PinnedFlowsResponse
```
**Error Codes:**
- `404` — tree not found or user lacks access
- `409` — max pins reached (15)
- `200` — idempotent success (pin already exists / already unpinned)
### 1c. Add Pinned Flows Backend Files
```
CREATE: backend/app/models/user_pinned_tree.py
MODIFY: backend/app/models/__init__.py — add UserPinnedTree import
MODIFY: backend/app/api/endpoints/trees.py — add pin/unpin/list-pinned/reorder endpoints
MODIFY: backend/app/schemas/tree.py — add PinnedFlow schema, add is_pinned to TreeListItem
MODIFY: backend/app/api/router.py — register pin routes (nested under trees router)
```
**Verify pinned flows work before proceeding:**
```bash
cd backend
alembic upgrade head
pytest tests/ -k "pin" -v # Run pin-related tests
# Manual: POST a pin, GET pinned list, verify response shapes
```
---
## Phase 2 — Backend: Remove Workspace System
### 2a. New Forward Migration (DO NOT use downgrade path)
> **⚠️ Critical:** The existing `036_add_workspaces.py` downgrade function drops `tree_categories.color`, which we want to keep. Create a new forward migration instead.
```bash
cd backend
alembic revision --autogenerate -m "remove_workspace_system"
```
The migration must:
```python
def upgrade():
# 1. Drop workspace_id FK from trees (if column exists)
op.drop_constraint('trees_workspace_id_fkey', 'trees', type_='foreignkey')
op.drop_column('trees', 'workspace_id')
# 2. Drop workspace_id FK from tree_categories (if column exists)
op.drop_constraint('tree_categories_workspace_id_fkey', 'tree_categories', type_='foreignkey')
op.drop_column('tree_categories', 'workspace_id')
# 3. Drop workspaces table
op.drop_table('workspaces')
# DO NOT drop tree_categories.color — we still use it
def downgrade():
# Recreate workspaces table and FKs if needed (reverse of above)
pass
```
### 2b. Delete Workspace Backend Files
```
DELETE: backend/app/api/endpoints/workspaces.py
DELETE: backend/app/models/workspace.py
DELETE: backend/app/schemas/workspace.py (if exists)
```
### 2c. Clean Up Orphaned Workspace References
> **⚠️ Important:** Workspace references exist beyond the obvious files. Scrub these:
| File | What to Remove |
|------|---------------|
| `backend/app/api/router.py` | Remove workspace route registration |
| `backend/app/models/__init__.py` (line 23, 55) | Remove `Workspace` import and `__all__` entry |
| `backend/app/models/account.py` (line 18, 49) | Remove `workspaces` relationship on Account model |
| `backend/app/models/category.py` (line 40) | Remove `workspace_id` column if present |
| `backend/app/models/tree.py` | Remove `workspace_id` column and relationship if present |
**Verification:**
```bash
cd backend
grep -r "workspace" app/ --include="*.py" -l
# Should only return this plan file and alembic migration history — no active code
pytest --override-ini="addopts="
# All tests must pass
```
**Migration smoke test (run against BOTH clean and existing DB):**
```bash
# Test on existing DB with workspace data:
alembic upgrade head
# Verify no errors, workspace tables gone, tree_categories.color still exists
# Test on clean DB (full migration chain):
dropdb patherly_test && createdb patherly_test
DATABASE_URL=postgresql://...patherly_test alembic upgrade head
# Verify clean run through all migrations
```
---
## Phase 3 — Frontend: Remove Workspace System
### 3a. Move sidebarCollapsed State First
The `sidebarCollapsed` state currently lives in `workspaceStore.ts`. Move it before deleting:
```typescript
// frontend/src/store/userPreferencesStore.ts — ADD these:
sidebarCollapsed: boolean;
toggleSidebar: () => void;
// Implementation:
sidebarCollapsed: localStorage.getItem('sidebar-collapsed') === 'true',
toggleSidebar: () => {
const next = !get().sidebarCollapsed;
localStorage.setItem('sidebar-collapsed', String(next));
set({ sidebarCollapsed: next });
},
```
> Note: `userPreferencesStore` already uses Zustand persist — verify the localStorage key name doesn't conflict.
### 3b. Delete Workspace Frontend Files
```
DELETE: frontend/src/store/workspaceStore.ts
DELETE: frontend/src/components/workspace/WorkspaceSwitcher.tsx
DELETE: frontend/src/components/workspace/WorkspaceCreateModal.tsx
DELETE: frontend/src/constants/workspaceLabels.ts
DELETE: frontend/src/types/workspace.ts (or remove Workspace type if shared file)
DELETE: frontend/src/api/workspaces.ts
DELETE: docs/mockups/resolutionflow-workspaces-mockup.html
```
**Before deleting `workspace/` directory**, move these components:
```
MOVE: frontend/src/components/workspace/CategoryList.tsx → frontend/src/components/sidebar/CategoryList.tsx
MOVE: frontend/src/components/workspace/TagCloud.tsx → frontend/src/components/sidebar/TagCloud.tsx
```
### 3c. Update Shell Files That Import Workspace Store
> **⚠️ Important:** These files are marked "keep" in the design system doc but they currently import workspace code. Each needs internal refactoring:
| File | Lines to Change | Action |
|------|----------------|--------|
| `AppLayout.tsx` (line 6, 17) | `import { useWorkspaceStore }` | Replace with `import { useUserPreferencesStore }` — use `sidebarCollapsed` and `toggleSidebar` from there |
| `TopBar.tsx` (line 6, 20) | `import { useWorkspaceStore }` | Replace with `useUserPreferencesStore` for `sidebarCollapsed`. Remove `getActiveWorkspace()` and `labels` — use static labels or `getFlowLabels()` |
| `Sidebar.tsx` (line 4, 111+) | `WorkspaceSwitcher` import and render | Remove workspace switcher component. Add pinned flows section and nav sub-items (Phase 4) |
### 3d. Clean Up Orphaned Frontend References
> **⚠️ Important:** Additional workspace references exist beyond the obvious files:
| File | What to Change |
|------|---------------|
| `frontend/src/types/index.ts` (line 11, 14) | Remove `Workspace` type export |
| `frontend/src/components/layout/QuickLaunch.tsx` | Replace workspace-dependent labels with static "New Flow" / "New Project" |
| `frontend/src/components/layout/CommandPalette.tsx` | Replace workspace-dependent search placeholder and result labels |
**Verification:**
```bash
cd frontend
grep -r "workspace" src/ --include="*.ts" --include="*.tsx" -l
# Should return nothing except possibly test files or comments
grep -r "workspaceStore\|WorkspaceSwitcher\|workspacesApi\|workspaceLabels" src/ -l
# Must return nothing
npm run build
# Must compile clean with zero errors
```
---
## Phase 4 — Label Renames (Repo-Wide Audit)
### 4a. Create Flow Type Labels
```typescript
// frontend/src/constants/flowLabels.ts (NEW — replaces workspaceLabels.ts)
export interface FlowTypeLabels {
navLabel: string;
singular: string;
plural: string;
newButton: string;
searchPlaceholder: string;
icon: string;
}
export const FLOW_TYPE_LABELS: Record<string, FlowTypeLabels> = {
all: {
navLabel: 'All Flows',
singular: 'Flow',
plural: 'Flows',
newButton: '+ Create Flow',
searchPlaceholder: 'Search flows, sessions, tags…',
icon: '📦',
},
troubleshooting: {
navLabel: 'Troubleshooting',
singular: 'Flow',
plural: 'Flows',
newButton: '+ New Troubleshooting Flow',
searchPlaceholder: 'Search troubleshooting flows…',
icon: '🔧',
},
procedural: {
navLabel: 'Projects',
singular: 'Project',
plural: 'Projects',
newButton: '+ New Project',
searchPlaceholder: 'Search projects, runbooks…',
icon: '📋',
},
};
export function getFlowLabels(typeFilter?: string): FlowTypeLabels {
if (typeFilter && typeFilter in FLOW_TYPE_LABELS) {
return FLOW_TYPE_LABELS[typeFilter];
}
return FLOW_TYPE_LABELS.all;
}
```
### 4b. Label Audit — Files Requiring Changes
Every instance of old terminology must be found and replaced. This is a **repo-wide pass**, not a targeted find-replace.
**User-facing label changes:**
| Old Label | New Label | Notes |
|-----------|-----------|-------|
| "All Trees" | "All Flows" | Sidebar nav, page titles |
| "Tree Editor" | "Flow Editor" | Sidebar nav |
| "New Tree" | "Create Flow" | Buttons, menus |
| "All Procedures" | "Projects" | Sub-nav item |
| "New Procedure" | "New Project" | Buttons, menus |
| "Procedure" (singular) | "Project" | Throughout UI |
**Known files with old labels (non-exhaustive):**
| File | Old Text | New Text |
|------|----------|----------|
| `Sidebar.tsx` | "All Trees", "Tree Editor" | "All Flows", "Flow Editor" |
| `TreeLibraryPage.tsx` (line 279, 298) | "All Trees", "Tree" references | "All Flows", "Flow" |
| `QuickStartPage.tsx` (line 150) | Workspace/procedure labels | Flow/Project labels |
| `QuickLaunch.tsx` | "New Tree", "New Procedure" | "Create Flow", "New Project" |
| `CommandPalette.tsx` | Search labels | Flow-based labels |
| `TopBar.tsx` | Search placeholder | Use `getFlowLabels()` or static "Search flows, sessions, tags…" |
**Catch-all verification:**
```bash
cd frontend
# Find any remaining user-facing "Tree" or "Procedure" labels (excluding variable names and imports)
grep -rn '".*Tree.*"' src/ --include="*.tsx" --include="*.ts" | grep -v "import\|//\|interface\|type \|treesApi\|tree_type\|treeId\|TreeNav\|TreeGrid\|TreeList\|TreeTable"
grep -rn '".*Procedure.*"' src/ --include="*.tsx" --include="*.ts" | grep -v "import\|//\|type "
```
> **Important:** Only rename **user-facing strings** (UI text, placeholder text, toast messages, page titles). Do NOT rename: variable names (`treesApi`, `TreeListItem`), route paths (`/trees`), database columns (`tree_type`), or API endpoints (`/api/v1/trees`). Internal code can say "tree" — users never see it.
### 4c. Acceptance Criteria for Label Audit
- [ ] No user-visible text says "Tree" (except proper nouns or technical docs)
- [ ] No user-visible text says "Procedure" — all say "Project"
- [ ] Search bar placeholder says "Search flows, sessions, tags…"
- [ ] Page title on library page says "Flow Library"
- [ ] "+ Create Flow" button on library page (or "+ New Project" when filtered to projects)
- [ ] Sidebar nav says "All Flows", "Flow Editor"
- [ ] Empty states use "flow" / "project" language
- [ ] Toast messages use "flow" / "project" language
---
## Phase 5 — Sidebar: Nav Sub-Items & Pinned Flows UI
### 5a. Extend NavItem for Children
```tsx
// frontend/src/components/layout/NavItem.tsx — extend props
interface NavItemProps {
href: string;
icon: LucideIcon;
label: string;
badge?: number | 'dot';
isActive?: boolean;
children?: NavSubItem[]; // NEW
}
interface NavSubItem {
href: string;
label: string;
count?: number;
isActive?: boolean;
}
```
**Sub-item rendering:**
- Indented `pl-9` (past parent icon)
- No icon, just text + optional count badge
- Font: `text-[0.8125rem] text-muted-foreground`, active: `text-foreground`
- Active: `bg-[var(--sidebar-active)]` but without the left gradient bar (only parent gets that)
- Sub-items always visible (not collapsible) — there are only 2
### 5b. Sidebar Structure
```
── PINNED ─────────────────── (collapsible section)
📧 Email Delivery Issues (click → start session or go to flow)
🔒 AD Account Lockout
👤 New User Onboarding
───────────────────────────────
📊 Dashboard
📦 All Flows 47
🔧 Troubleshooting 29
📋 Projects 18
✏️ Flow Editor
⏱️ Sessions 4
📄 Exports
📚 Step Library •
───────────────────────────────
CATEGORIES
● Networking 12
● Active Directory 8
● Email 11
───────────────────────────────
POPULAR TAGS
[vpn] [dns] [exchange] [onboarding]
═══════════════════════════════
👥 Team
⚙️ Settings
```
**Behavior:**
- Clicking "All Flows" → `/trees` (no type filter)
- Clicking "Troubleshooting" → `/trees?type=troubleshooting`
- Clicking "Projects" → `/trees?type=procedural`
- When a sub-item is active, parent "All Flows" stays highlighted (dimmer state)
- Badge counts update based on actual tree counts by type
### 5c. Pinned Flows Section
```tsx
// frontend/src/components/sidebar/PinnedFlowsSection.tsx (NEW)
interface PinnedFlowsSectionProps {
flows: PinnedFlow[];
onFlowClick: (treeId: string) => void;
onUnpin: (treeId: string) => void;
}
```
**Behavior:**
- Each pinned item: emoji + name (truncated with ellipsis) + hover reveals quick-start button
- Right-click context menu: "Start Session", "Edit Flow", "Unpin from Sidebar"
- Empty state: "⭐ Pin your most-used flows here" in `text-xs text-muted-foreground`
- Section header has collapse chevron
- Max 15 items shown; section scrolls internally if needed
- Drag-to-reorder (calls `PATCH /api/v1/trees/pinned/reorder`)
### 5d. Pinned Flows Frontend Wiring
```
CREATE: frontend/src/api/pinnedFlows.ts — pinTree(id), unpinTree(id), listPinned(), reorderPinned(order)
CREATE: frontend/src/components/sidebar/PinnedFlowsSection.tsx
MODIFY: frontend/src/types/tree.ts (or index.ts) — add is_pinned?: boolean to TreeListItem, add PinnedFlow type
MODIFY: frontend/src/api/trees.ts — add is_pinned to list response handling
MODIFY: frontend/src/components/layout/Sidebar.tsx — import and render PinnedFlowsSection above nav
MODIFY: frontend/src/pages/TreeLibraryPage.tsx — add pin star to flow cards (visible on hover, filled if pinned)
MODIFY: flow card three-dot menu — add "Pin to Sidebar" / "Unpin from Sidebar" action
```
**Pin/unpin interaction:**
- Toast on pin: "📌 Pinned **{name}** to sidebar"
- Toast on unpin: "Unpinned **{name}**"
- Library flow cards show subtle star icon on hover; filled star if pinned
- Pin star click calls API, optimistically updates UI
---
## Phase 6 — Library Page Cleanup
### 6a. Remove Folder Sidebar Panel
> **⚠️ Important:** `TreeLibraryPage.tsx` has deep folder state dependencies (lines 9, 34, 261+). This is not a simple component removal.
**What to remove:**
- `FolderSidebar` component import and rendering (the persistent left panel)
- `FolderEditModal` import and state
- The CSS column that gives FolderSidebar its own grid track
- `mobileFolderOpen` state
**What to KEEP:**
- `selectedFolderId` state — keep for now, wire to a future "Filter by Folder" dropdown
- `folders` state and `foldersApi.list()` call — keep data available
- `FolderSidebar.tsx` and `FolderEditModal.tsx` files — do not delete, just stop rendering them
- All folder-related backend code (models, API, database tables) — untouched
**Replacement UX (deferred but noted):**
- Future: "Filter by Folder" dropdown in the filters bar, or "Move to Folder" in the three-dot menu
- For now: folder filtering is simply not visible in the UI. The data model and API remain intact.
**Layout change:**
- Library page becomes full-width within the main content area (no second sidebar column)
- Grid goes from `sidebar | folders | content``sidebar | content`
### 6b. Verification
```bash
cd frontend && npm run build
# Must compile clean
```
Manual checks:
- [ ] Library page is full-width (no left folder panel)
- [ ] No JavaScript errors in browser console related to folder state
- [ ] Category filtering from sidebar clicks still works
- [ ] Tag filtering from sidebar clicks still works
---
## Complete File Manifest
### Delete (11 files)
| File | Reason |
|------|--------|
| `frontend/src/store/workspaceStore.ts` | Replaced by userPreferencesStore (sidebarCollapsed) |
| `frontend/src/components/workspace/WorkspaceSwitcher.tsx` | Feature removed |
| `frontend/src/components/workspace/WorkspaceCreateModal.tsx` | Feature removed |
| `frontend/src/constants/workspaceLabels.ts` | Replaced by flowLabels.ts |
| `frontend/src/types/workspace.ts` | Type no longer needed |
| `frontend/src/api/workspaces.ts` | API removed |
| `backend/app/api/endpoints/workspaces.py` | API removed |
| `backend/app/models/workspace.py` | Model removed |
| `backend/app/schemas/workspace.py` | Schema removed (if exists) |
| `docs/mockups/resolutionflow-workspaces-mockup.html` | Outdated mockup |
### Move (2 files)
| From | To |
|------|----|
| `frontend/src/components/workspace/CategoryList.tsx` | `frontend/src/components/sidebar/CategoryList.tsx` |
| `frontend/src/components/workspace/TagCloud.tsx` | `frontend/src/components/sidebar/TagCloud.tsx` |
Then delete the empty `frontend/src/components/workspace/` directory.
### Create (6+ files)
| File | Purpose |
|------|---------|
| `backend/alembic/versions/0XX_remove_workspace_system.py` | Drop workspace tables/columns |
| `backend/alembic/versions/0XX_add_user_pinned_trees.py` | New pinned flows table |
| `backend/app/models/user_pinned_tree.py` | UserPinnedTree SQLAlchemy model |
| `frontend/src/constants/flowLabels.ts` | Flow type label constants |
| `frontend/src/api/pinnedFlows.ts` | Pin/unpin API client |
| `frontend/src/components/sidebar/PinnedFlowsSection.tsx` | Pinned flows sidebar component |
### Modify (14 files — key changes only)
| File | Changes |
|------|---------|
| `backend/app/api/router.py` | Remove workspace routes, add pin routes |
| `backend/app/models/__init__.py` | Remove Workspace import (line 23, 55), add UserPinnedTree |
| `backend/app/models/account.py` | Remove `workspaces` relationship (line 18, 49) |
| `backend/app/models/category.py` | Remove `workspace_id` column (line 40) if present |
| `backend/app/models/tree.py` | Remove `workspace_id` column/relationship if present |
| `backend/app/api/endpoints/trees.py` | Add pin/unpin/list-pinned/reorder endpoints |
| `backend/app/schemas/tree.py` | Add PinnedFlow schema, add `is_pinned` to tree list |
| `frontend/src/store/userPreferencesStore.ts` | Absorb `sidebarCollapsed` + `toggleSidebar` |
| `frontend/src/components/layout/AppLayout.tsx` | Replace workspaceStore with userPreferencesStore |
| `frontend/src/components/layout/TopBar.tsx` | Replace workspaceStore, static search labels |
| `frontend/src/components/layout/Sidebar.tsx` | Remove workspace switcher, add pinned section + nav sub-items |
| `frontend/src/components/layout/NavItem.tsx` | Add `children` sub-item support |
| `frontend/src/pages/TreeLibraryPage.tsx` | Remove FolderSidebar, update labels, add pin star |
| `frontend/src/components/layout/QuickLaunch.tsx` | Update action labels |
| `frontend/src/components/layout/CommandPalette.tsx` | Update search labels |
| `frontend/src/pages/QuickStartPage.tsx` | Update workspace/procedure labels (line 150) |
| `frontend/src/types/index.ts` | Remove Workspace export (line 11, 14), add PinnedFlow |
---
## Verification Checklist
### Automated
```bash
# Backend
cd backend
alembic upgrade head # Migration applies clean
pytest --override-ini="addopts=" # All tests pass
grep -r "workspace" app/ --include="*.py" -l # No active workspace refs
# Frontend
cd frontend
npm run build # Compiles clean, zero errors
grep -r "workspaceStore\|WorkspaceSwitcher\|workspacesApi\|workspaceLabels" src/ -l
# Returns nothing
```
### Manual UI Checks
- [ ] Sidebar shows "All Flows" with "Troubleshooting" and "Projects" sub-items — no workspace switcher
- [ ] Clicking "Troubleshooting" filters library to `?type=troubleshooting`
- [ ] Clicking "Projects" filters library to `?type=procedural`
- [ ] Clicking "All Flows" removes type filter
- [ ] Sub-item counts reflect actual flow counts per type
- [ ] Pin a flow from the library card three-dot menu → appears in sidebar "PINNED" section
- [ ] Unpin a flow → disappears from sidebar
- [ ] Pinned flow click navigates to that flow
- [ ] Library page is full-width (no folder sidebar panel)
- [ ] Search bar is centered in top bar
- [ ] Keyboard shortcut shows "Ctrl+K" on Windows, "⌘K" on Mac
- [ ] All user-visible labels say "Flow" / "Project", never "Tree" / "Procedure"
- [ ] Empty states use correct terminology
- [ ] Toast messages use correct terminology
- [ ] Command palette search works with new labels
- [ ] Quick Launch actions show correct labels