# 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)*