# CLAUDE.md - Patherly / ResolutionFlow Project Context > **Last Updated:** February 14, 2026 --- ## Project Overview **Patherly** (user-facing brand: **ResolutionFlow**) is a **SaaS product for MSP professionals**. It provides troubleshooting decision trees that guide engineers through proven troubleshooting paths, capture decisions and notes, and generate professional ticket documentation. **Target Market:** MSP companies — IT service providers managing infrastructure and support for multiple clients. **SaaS Context:** Multi-tenant design — teams represent MSP companies, trees shared within teams, tiered access (super_admin, team_admin, engineer, viewer). ### Branding | Context | Name Used | |---------|-----------| | Repository / directory / database / Docker | `patherly` / `patherly_postgres` | | Backend, frontend UI, production URLs | **ResolutionFlow** | - **Design:** Dark-first with purple gradient accents (`#818cf8` → `#a78bfa`). NOT monochrome — use gradient for primary buttons, active nav indicators, stat highlights, and brand text. - **Fonts:** Plus Jakarta Sans (`font-heading`, headings/titles), Inter (`font-sans`, body text), Outfit (`font-label`, labels/badges/counts) — loaded via Google Fonts - **Logo:** Inline SVG in `BrandLogo.tsx` (decision-tree icon with gradient). Wordmark: "Resolution" in white + "Flow" in `text-gradient-brand` - **Brand assets:** `brand-assets/` (source SVGs + brand-guide.html), `frontend/src/assets/brand/` (app assets), `frontend/public/icons/` (favicon) - **CSS utilities:** `text-gradient-brand`, `bg-gradient-brand`, `bg-gradient-brand-hover` (defined in `tailwind.config.js` and `index.css`) - **Layout:** App shell with persistent sidebar + top bar + main workspace (CSS Grid). See [UI-DESIGN-SYSTEM.md](UI-DESIGN-SYSTEM.md) - **Workspace system:** Top-level context switcher (Troubleshooting, Procedures, Policies, Finance). Sidebar categories, tags, stats, and content adapt per workspace. See [UI-DESIGN-SYSTEM.md](UI-DESIGN-SYSTEM.md) - **Rebrand guide:** [REBRAND-IMPLEMENTATION-GUIDE.md](REBRAND-IMPLEMENTATION-GUIDE.md) - **Interactive mockup:** `docs/mockups/resolutionflow-workspaces-mockup.html` (open in browser for visual reference) **Component styling rules:** - Primary buttons: `bg-gradient-brand` with `shadow-lg shadow-primary/20`, hover lifts with stronger shadow - Secondary buttons: `bg-card` with `border-border`, hover brightens border - Active nav items: `bg-primary/8` background + 3px left gradient accent bar - Stat values: use `text-gradient-brand` for highlighted metrics - Status colors: green (`text-green-500`) for success, amber (`text-amber-500`) for in-progress, red (`text-red-500`) for error/critical - Category dots: 8px colored circles using the category color palette - Tags/badges: `font-label` (Outfit), small rounded chips with `bg-card border-border` - Cards: `bg-card border-border rounded-xl`, hover brightens border - Section labels: `font-label text-[0.6875rem] uppercase tracking-wide text-muted-foreground` When adding new pages/components: use "ResolutionFlow" branding, purple gradient accent theme, `bg-card` containers, `text-foreground`/`text-muted-foreground` hierarchy. Primary actions use `bg-gradient-brand`. Pages render inside the app shell (CSS Grid: topbar + sidebar + main). Reference [UI-DESIGN-SYSTEM.md](UI-DESIGN-SYSTEM.md) for layout patterns, workspace context, and component specs. --- ## Current State - **Phase:** Phase 2.5 - Step Library Foundation (In Progress) - **Backend:** Complete (25+ API endpoints, 100+ integration tests) - **Frontend:** Core features complete, Tree Editor functional - **Database:** PostgreSQL with Docker, 30+ migrations - **Detailed status:** [CURRENT-STATE.md](CURRENT-STATE.md) ### What's In Progress - Procedural flows reusability and run lifecycle improvements (Phase 2) - Step Library Frontend UI ### Recently Completed - Session sharing: ShareSessionModal, SharedSessionPage, MySharesPage, share links with copy/manage - Procedural editor UX: section headers as step type, "More Options" collapsible, URL intake field, tag input improvements - Type-aware routing: centralized `getTreeNavigatePath` helper, procedural resume support, safety redirects - Export improvements (Phases A-C): step cutoff, summary block, detail levels, editable preview, sensitive data redaction --- ## Tech Stack ### Backend - **Framework:** Python FastAPI - **Database:** PostgreSQL 16 (async via SQLAlchemy 2.0 + asyncpg) - **Migrations:** Alembic - **Auth:** JWT (python-jose) + bcrypt, refresh token rotation (JTI-based) - **Validation:** Pydantic v2 ### Frontend - **Framework:** React 19 + Vite + TypeScript - **Styling:** Tailwind CSS v3 — dark-first with purple gradient accents (see Branding section) - **State:** Zustand (with immer + zundo for undo/redo) - **Routing:** React Router v7 - **API Client:** Axios with token refresh interceptor - **Icons:** Lucide React --- ## Key Project Structure ``` patherly/ ├── backend/ │ ├── app/ │ │ ├── main.py # FastAPI entry point │ │ ├── api/endpoints/ # Route handlers (auth, trees, sessions, admin, steps, etc.) │ │ ├── api/deps.py # Auth dependencies │ │ ├── api/router.py # Route registration │ │ ├── core/ # config, database, permissions, security, audit, rate_limit │ │ ├── models/ # SQLAlchemy models │ │ └── schemas/ # Pydantic schemas │ ├── alembic/ # Database migrations (001-029+) │ ├── scripts/ # seed_data.py, seed_trees.py │ └── tests/ # pytest integration tests ├── frontend/ │ ├── src/ │ │ ├── api/ # Axios client + endpoint modules │ │ ├── components/ # common, layout, tree-editor, session, procedural, procedural-editor, library, step-library, ui │ │ ├── hooks/ # usePermissions, useSessionTimer, useKeyboardShortcuts │ │ ├── pages/ # All page components │ │ ├── store/ # Zustand stores (auth, treeEditor, proceduralEditor, userPreferences) │ │ └── types/ # TypeScript interfaces │ └── tailwind.config.js ├── CLAUDE.md # This file ├── CURRENT-STATE.md # Detailed feature status ├── LESSONS-LEARNED.md # Bugs and fixes (READ THIS!) └── docs/plans/ # Design docs & implementation plans ``` --- ## Environment Variables ### Backend (`backend/.env`) ```bash APP_NAME=ResolutionFlow DEBUG=true DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/patherly DATABASE_URL_SYNC=postgresql://postgres:postgres@localhost:5432/patherly SECRET_KEY= ACCESS_TOKEN_EXPIRE_MINUTES=5 REFRESH_TOKEN_EXPIRE_DAYS=7 REQUIRE_INVITE_CODE=true ``` ### Frontend (`frontend/.env.local` - optional) ```bash VITE_API_URL=http://localhost:8000 ``` --- ## Development Commands ```powershell # Start PostgreSQL docker start patherly_postgres # Backend (from backend/) .\venv\Scripts\Activate uvicorn app.main:app --reload # Frontend (from frontend/) npm run dev # Run tests (from backend/) pytest --override-ini="addopts=" # First time only: create test database docker exec -it patherly_postgres psql -U postgres -c "CREATE DATABASE patherly_test;" # Frontend build (IMPORTANT: stricter than tsc --noEmit — always use as final check) cd frontend && npm run build # Database migrations cd backend && alembic upgrade head alembic revision --autogenerate -m "Description" # Access PostgreSQL docker exec -it patherly_postgres psql -U postgres -d patherly # Seed data cd backend && pip install httpx && python -m scripts.seed_trees ``` ### URLs - Frontend: http://localhost:5173 - Backend API: http://localhost:8000 - API Docs: http://localhost:8000/api/docs --- ## Critical Lessons Learned **Full reference:** [LESSONS-LEARNED.md](LESSONS-LEARNED.md) — read before making changes! ### Top Gotchas (most commonly hit) **1. DateTime Handling — Always timezone-aware:** ```python # CORRECT created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)) # NEVER use datetime.utcnow() ``` **2. SQLAlchemy Async — No lazy loading on new objects:** ```python # WRONG — MissingGreenlet error new_tree = Tree(...); db.add(new_tree); await db.flush() new_tree.tags.append(tag) # Lazy load fails! # CORRECT — Use direct SQL for junction tables await db.execute(tree_tag_assignments.insert().values(tree_id=new_tree.id, tag_id=tag.id)) ``` **3. React State — Don't store object snapshots:** ```tsx // WRONG — snapshot won't update const [editingNode, setEditingNode] = useState(node) // CORRECT — store ID, derive object const [editingNodeId, setEditingNodeId] = useState(node.id) const editingNode = editingNodeId ? findNode(editingNodeId, tree?.tree_structure) : null ``` **4. Modal Draft State — Exclude store-managed fields:** ```tsx const { children, ...draftWithoutChildren } = draft updateNode(node.id, draftWithoutChildren) // Don't overwrite children ``` **5. Multiple FKs to same table — Specify `foreign_keys` on BOTH sides:** ```python author = relationship("User", foreign_keys=[author_id], back_populates="trees") ``` **6. PostgreSQL NULL in UUID columns:** ```sql SELECT 'tag', 'slug', NULL::uuid as team_id -- Must cast NULL to uuid ``` **7. API Path Gotcha:** Frontend `apiClient` baseURL is `http://localhost:8000/api/v1` — use relative paths WITHOUT `/api/v1/` prefix (e.g., `/admin/users` not `/api/v1/admin/users`). Invite codes endpoint is `/invites` (NOT `/invite-codes`). **8. CORS errors can mask 500s:** Check backend logs first. Also run `alembic upgrade head` after pulling changes. **11. CORS `expose_headers` for custom response headers:** Browsers block frontend from reading custom headers (e.g. `X-Redaction-Summary`) unless CORS middleware includes `expose_headers=["X-Custom-Header"]`. Must be set in BOTH CORS branches in `main.py`. **9. Public endpoints with optional auth:** Use manual `_get_optional_user(request, db)` helper, NOT `Optional[User]` param (FastAPI treats it as Pydantic field). **10. React Router — Clear dirty state before navigation:** ```tsx markSaved() // Clear isDirty BEFORE navigate() navigate(`/trees/${newTree.id}/edit`) ``` **12. TreeStructure vs Tree types:** `TreeStructure` is for node structure only — it does NOT have `tree_type`, `name`, etc. Those are on `Tree`. JSONB tree snapshots need `TreeStructure & Record` for extra fields. **13. Login redirect state format:** `navigate('/login', { state: { from: { pathname: '/path' } } })` — LoginPage expects `state.from.pathname` (object), NOT a plain string. **14. Type-aware routing for trees/sessions:** Always use `getTreeNavigatePath(treeId, treeType)` from `@/lib/routing` instead of hardcoding `/trees/:id/navigate`. Procedural flows use `/flows/:id/navigate`. Session resume passes `{ state: { sessionId } }`. TreeNavigationPage has a safety redirect for procedural trees. **15. Session sharing types:** `TreeSnapshot` extends `TreeStructure` but session snapshots from the API include extra fields like `tree_type`. Use `tree_snapshot?.tree_type` to determine flow type from session data. --- ## RBAC & Permissions - **Role hierarchy:** super_admin > team_admin > engineer > viewer - **Team Admin:** `role='engineer'` + `is_team_admin=True` + valid `team_id` - **Backend deps:** `get_current_active_user(user, db)` (any active + auto-downgrades expired trials), `require_engineer_or_admin` (blocks viewers), `require_admin` (super admin only) - **Never use** `role == "admin"` — use `is_super_admin` instead - **Frontend:** `usePermissions()` hook for all permission checks - **Centralized:** `backend/app/core/permissions.py`, `frontend/src/hooks/usePermissions.ts` --- ## Monochrome Design System - **Backgrounds:** `bg-black`, subtle radial gradients - **Cards:** `glass-card rounded-2xl` (NOT `bg-card border-border`) - **Buttons:** Primary: `bg-white text-black hover:bg-white/90`. Secondary: `border border-white/10 text-white/60 hover:bg-white/10` - **Inputs:** `border-white/10 bg-black/50 text-white` + focus: `border-white/30 ring-white/20` - **Text:** `text-white` → `text-white/70` → `text-white/40` → `text-white/30` - **Borders:** `border-white/[0.06]` or `border-white/10` - **Functional color only:** emerald-400 (success), red-400 (error), yellow-400 (warning), blue-400 (info) --- ## Frontend Patterns - **Component guidelines:** Use `cn()` from `@/lib/utils`, Lucide icons (wrap in `` for title), modals with fixed header/footer - **Type organization:** Create in `types/`, export from `types/index.ts`, import with `import type { T } from '@/types'` - **Scratchpad overlay:** `position: fixed`, `onOpenChange` callback for parent padding adjustment, `right-2` positioning - **Custom step flow:** `CustomStepModal` → `PostStepActionModal` → `ContinuationModal` → custom step view. Key state: `pendingStep`, `pendingContinuationNodeId`, `customBranchMode`, `branchOriginNodeId`. Use `findCustomStep()` not `findNode()` for custom step UUIDs. - **Session sharing:** `ShareSessionModal` manages share links, `SharedSessionPage` renders public/account views. Helper utils in `lib/sessionShare.ts`. Share URLs use `/shared/sessions/:token`. - **Procedural navigation:** `ProceduralNavigationPage` handles intake forms, step-by-step execution, and resume via `location.state.sessionId`. Uses `StepChecklist`, `StepDetail`, `ProgressBar`, `CompletionSummary` components. - **Routing helper:** Use `getTreeNavigatePath()` and `getTreeEditorPath()` from `@/lib/routing` for all tree/session navigation. --- ## Common Tasks - **New endpoint:** Create in `endpoints/` → add to `router.py` → schema in `schemas/` → tests → frontend API client - **New page:** Create in `pages/` → add route in `router.tsx` → nav link in `AppLayout.tsx` - **New public route (no auth):** Add at top level in `router.tsx` alongside `/login`, `/register` — NOT inside the `ProtectedRoute`/`AppLayout` children. - **Schema change:** Update model → `alembic revision --autogenerate -m "desc"` → review → `alembic upgrade head` - **New frontend API module:** Types in `types/` → export from `types/index.ts` → client in `api/` → export from `api/index.ts` --- ## Coding Standards ### Python - Type hints everywhere, async/await for DB, Pydantic for validation, `DateTime(timezone=True)` always ### TypeScript - Interfaces for all data, `const` over `let`, functional components + hooks, reusable logic in custom hooks ### Git - Format: `type: description` (feat, fix, refactor, docs, test, chore) - Always include `Co-Authored-By: Claude Opus 4.6 ` - Always create feature branch BEFORE committing: `git checkout -b feat/feature-name` - Large features: commit per phase with `npm run build` validation --- ## Deployment (Railway) - **Production:** `resolutionflow.com` (frontend), `api.resolutionflow.com` (backend) - Auto-deploys on push to `main` - PR environments auto-created (need manual domain generation in Railway dashboard) - PR envs need `VITE_API_URL` set with `https://` prefix on frontend service - `ALLOW_RAILWAY_ORIGINS=true` enables CORS for `*.up.railway.app` - Super admin utility: `backend/make_superadmin_simple.py list|` --- ## Future Roadmap - **Phase 3:** File attachments, offline mode, client context, analytics - **Phase 4:** PSA integrations (ConnectWise, Kaseya), PowerShell automation, enterprise SSO --- ## Quick Reference | What | Where | |------|-------| | API Docs | http://localhost:8000/api/docs | | Detailed Status | [CURRENT-STATE.md](CURRENT-STATE.md) | | Bugs & Fixes | [LESSONS-LEARNED.md](LESSONS-LEARNED.md) | | Feature Specs | [04-FEATURE-SPECIFICATIONS.md](04-FEATURE-SPECIFICATIONS.md) | | Design System | [docs/plans/Frontend/DESIGN_SYSTEM_GUIDE.md](docs/plans/Frontend/DESIGN_SYSTEM_GUIDE.md) |