- Update phase to Go-to-Market Validation (Pre-PMF) - Update in-progress and recently completed sections - Lesson 78: Landing page subtitle branding - Lesson 79: Custom modal mobile-responsive pattern - Lesson 80: TopBar search collapses to icon on mobile - Lesson 81: No transition: all in CSS - Lesson 82: Bun PATH setup on devserver01 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
32 KiB
CLAUDE.md - Patherly / ResolutionFlow Project Context
Last Updated: March 21, 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 glassmorphism with ice-cyan accent gradient (
#06b6d4→#22d3ee). Charcoal backgrounds, frosted-glass cards withbackdrop-filter: blur(), orchestrated page-load animations, bold display typography. Design doc: docs/plans/2026-03-03-aesthetic-redesign-design.md - Fonts: Bricolage Grotesque (
font-heading, headings/titles), IBM Plex Sans (font-sans, body text), JetBrains Mono (font-label, labels/badges/timestamps) — loaded via Google Fonts - Logo: Inline SVG in
BrandLogo.tsx(decision-tree icon with cyan gradient). Wordmark: "Resolution" intext-foreground+ "Flow" intext-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 inindex.cssvia@theme). Glass utilities:.glass-card(interactive,scale(1.02)hover),.glass-card-static(no hover transform),.active-glow(breathing cyan shadow) - Layout: App shell with persistent sidebar + top bar + main content (CSS Grid). Two fixed atmosphere orbs (cyan top-right, purple bottom-left) behind the shell for ambient glow. See UI-DESIGN-SYSTEM.md
- Navigation: Sidebar nav with type sub-items (All Flows → Troubleshooting / Projects / Maintenance). Pinned flows section for quick access. NO workspace switcher. See UI-DESIGN-SYSTEM.md
- Terminology: User-facing label is "Flows" (not "Trees"). Procedural flows are called "Projects" in the UI. Maintenance flows are called "Maintenance" in the UI.
tree_typecolumn values unchanged in DB. - Rebrand guide: REBRAND-IMPLEMENTATION-GUIDE.md
Component styling rules:
- Primary buttons:
bg-gradient-brand(cyan135deg) withshadow-lg shadow-primary/20, hoveropacity-0.9, activescale(0.97) - Secondary buttons:
bg-[rgba(255,255,255,0.04)]withborder-[rgba(255,255,255,0.06)], hover brightens border - Active nav items:
bg-primary/10background + 3px left cyan gradient accent bar - Stat values: use
text-gradient-brandfor highlighted metrics - Status colors: emerald-400 (success), amber-400 (in-progress), rose-500 (error/critical)
- Category dots: 8px colored circles using the category color palette
- Tags/badges:
font-label(JetBrains Mono), small rounded chips withbg-card border-border - Cards:
.glass-card(interactive) or.glass-card-static(non-interactive) — semi-transparent bg withbackdrop-filter: blur(16px),border-radius: 16px - Section labels:
font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground
When adding new pages/components: use "ResolutionFlow" branding, ice-cyan gradient accent theme, .glass-card / .glass-card-static containers, text-foreground/text-muted-foreground hierarchy. Primary actions use bg-gradient-brand. Pages render inside the app shell (CSS Grid: topbar + sidebar + main). Use "Flows" not "Trees" in all user-facing text; use "Projects" not "Procedures" for procedural flows. Reference UI-DESIGN-SYSTEM.md for layout patterns, navigation, and component specs.
Implementation Principles
- Prefer correct architecture over minimal diff
- If two approaches exist, implement the one that scales, not the one that's faster to write
- Flag any "simpler approach" tradeoffs for product owner review before proceeding
Current State
- Phase: Go-to-Market Validation (Pre-PMF)
- Backend: Complete (35+ API endpoints, 100+ integration tests)
- Frontend: Core features complete, Tree Editor functional
- Database: PostgreSQL with Docker, 75 migrations
- Detailed status: CURRENT-STATE.md
What's In Progress
- Go-to-market validation: shadow MSP engineers, get product in front of real users
- Landing page polish: mobile responsiveness, design audit fixes
- Remaining open issues: #66 Templates + Import/Export, #60 Recurring Issue Detection, #58 Step Feedback Flag
Recently Completed
- Landing page design audit: hamburger menu, Privacy/Terms pages, branding alignment, mobile responsive modals, section spacing
- Root directory cleanup: archived 9 completed docs, tracked marketing assets
- GitHub issues triage: closed 10 stale issues (6 completed, 4 deferred)
- FlowPilot Phase 2: PSA integration, escalation handoff, session pause/resume, mid-session ticket linking
- Step Library Foundation
- AI chat session conclusion: outcome tracking, AI-generated ticket summaries, resume flow
- Survey completion: email-to-self, thank-you page, admin read/unread/archive/delete management
- Survey system: public survey page, admin invite tracking, response viewer with CSV export
- Email verification: tokens, banner, admin toggle (platform setting)
- AI assistant: in-session copilot panel, standalone chat with RAG
- Slate & Ice aesthetic redesign: glassmorphism, brand fonts, orchestrated animations
- Account management: profile settings, delete/leave/transfer, chat retention
- Maintenance flows: batch session launch, saved target lists, APScheduler scheduling
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
- Scheduling: APScheduler 3.x (async, in-process with FastAPI lifespan) + croniter + pytz
Frontend
- Framework: React 19 + Vite + TypeScript
- Styling: Tailwind CSS v4 (
@tailwindcss/viteplugin, CSS-only config inindex.css) — dark-first with ice-cyan 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, survey, copilot, assistant_chat, psa_connections)
│ │ │ ├── flow_proposals.py # Knowledge Flywheel review queue CRUD
│ │ │ └── flowpilot_analytics.py # FlowPilot dashboard metrics
│ │ ├── api/deps.py # Auth dependencies (includes require_team_admin)
│ │ ├── api/router.py # Route registration
│ │ ├── core/ # config, database, permissions, security, audit, rate_limit
│ │ ├── models/ # SQLAlchemy models (includes FlowProposal)
│ │ ├── schemas/ # Pydantic schemas
│ │ ├── services/psa/ # PSA provider abstraction (base, connectwise/, cache, encryption, registry, types)
│ │ ├── services/knowledge_flywheel.py # AI session analysis → flow proposals
│ │ ├── services/knowledge_flywheel_scheduler.py # APScheduler job for batch analysis
│ │ └── services/knowledge_gap_service.py # Weak options & escalation signal detection
│ ├── 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, dashboard, tree-editor, session, procedural, procedural-editor, library, step-library, ui, flowpilot
│ │ ├── hooks/ # usePermissions, useSessionTimer, useKeyboardShortcuts
│ │ ├── pages/ # All page components
│ │ ├── store/ # Zustand stores (auth, treeEditor, proceduralEditor, userPreferences)
│ │ └── types/ # TypeScript interfaces
│ └── (Tailwind v4: CSS-only config in src/index.css)
├── docs/plans/archive/ # Archived design/impl docs (pre-March 2026)
├── CLAUDE.md # This file
├── CURRENT-STATE.md # Detailed feature status
├── LESSONS-LEARNED.md # (Deprecated — consolidated into CLAUDE.md)
└── docs/plans/ # Design docs & implementation plans
Environment Variables
Backend (backend/.env)
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=<openssl rand -hex 32>
ACCESS_TOKEN_EXPIRE_MINUTES=5
REFRESH_TOKEN_EXPIRE_DAYS=7
REQUIRE_INVITE_CODE=true
Frontend (frontend/.env.local - optional)
VITE_API_URL=http://localhost:8000
ConnectWise PSA Integration
ResolutionFlow integrates with ConnectWise PSA (formerly Manage) as the primary PSA integration. All ConnectWise API reference materials live in docs/connectwise/.
Best Practices Documentation
Official ConnectWise developer guides live in docs/connectwise/best-practices/. Read these BEFORE implementing any CW API integration code:
PSA-API-Requests.md— HTTP methods, response codes, condition query syntax, PATCH format, URL encoding, partial responses, custom fields. READ FIRST.PSA-Callbacks.md— Callback type/level matrix, retry behavior, URL parameter gotcha, HMAC signature verification.PSA-Pagination.md— Navigable vs Forward-Only pagination, Link headers, while-loop pattern.PSA-Service-Tickets.md— Ticket field philosophy, recommended field mappings.PSA-Versioning.md— Pin API version via Accept header. Useapplication/vnd.connectwise.com+json; version=2025.16.PSA-Cloud-URL-Formatting.md— Dynamic base URL construction via/login/companyinfo/{companyId}.Bundled-Requests.md— Batch multiple API calls into one request via/system/bundles.PSA-Markdown.md— Ticket notes support markdown. Format session documentation output accordingly.PSA-Company-Synchronization.md— Filter companies by Status/Type for mapping UI.PSA-Data-Protection.md— Security role model, request minimal permissions (MY not ALL).
Reference Files (read in this order)
docs/connectwise/CONNECTWISE-API-REFERENCE.md— Read FIRST. Quick reference covering auth patterns, tiered endpoint map, key field mappings, and integration architecture flows.docs/connectwise/connectwise-psa-resolutionflow-reference.json— Extracted OpenAPI 3.0.1 spec (v2025.16) with only the 670 endpoints and 342 schemas relevant to ResolutionFlow. Use for exact field types, request/response shapes, and parameter details.docs/connectwise/connectwise-psa-openapi-full.json— Complete ConnectWise PSA OpenAPI spec (1838 endpoints, 842 schemas). Only consult if you need an endpoint outside the extracted subset.
Integration Architecture
- Session → Ticket Notes: Post auto-generated session documentation to ConnectWise tickets as internal analysis notes via
POST /service/tickets/{id}/notes - Ticket Context → Session Runner: Pull ticket details, company info, and attached configurations to give FlowPilot AI real-world context
- Callbacks: Register webhooks via
/system/callbacksfor real-time ticket event notifications to suggest relevant Flows
Key Implementation Rules
- Auth: API Key auth (Base64 of
companyId+publicKey:privateKey) +clientIdheader on every request clientIdis server-side config (CW_CLIENT_IDinconfig.py) — identifies the ResolutionFlow app, NOT per-tenant. Per-connection credentials:company_id,public_key,private_key,server_url- All PSA integration code in
services/psa/— provider pattern withPSAProviderabstract base class,ConnectWiseProviderimplementation,PsaProviderRegistryfor multi-PSA dispatch - PSA endpoints in
api/endpoints/psa_connections.py— connection CRUD, ticket ops, member mapping - Credentials encrypted at rest via
services/psa/encryption.py(Fernet) - Each MSP tenant provides their own CW credentials — ResolutionFlow stores these per-team, never per-user
- Design for the Autotask integration following the same service layer pattern (future PSA)
- In-memory TTL cache in
services/psa/cache.pyfor board/status/priority lookups - Respect CW API: paginate with max 1000 per page, handle retries gracefully
Development Commands
# Start PostgreSQL
docker start patherly_postgres
# Backend (from backend/)
source venv/bin/activate # Linux/Mac
# .\venv\Scripts\Activate # Windows
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" --rev-id=NNN # NNN = next sequential number
# Access PostgreSQL
docker exec -it patherly_postgres psql -U postgres -d patherly
# Seed data
cd backend && pip install httpx && python -m scripts.seed_trees
# CI/CD debugging
gh run list --limit 5 # Recent CI runs
gh run view <id> --log-failed # Failed job logs
gh run watch <id> --exit-status # Watch run until complete
gh run view <id> --json jobs --jq '.jobs[] | {name: .name, conclusion: .conclusion}'
URLs
- Frontend: http://localhost:5173
- Backend API: http://localhost:8000
- API Docs: http://localhost:8000/api/docs
Test Users (seeded via scripts/seed_test_users.py)
- All share password:
TestPass123! admin@resolutionflow.example.com(super_admin),teamadmin@resolutionflow.example.com(team_admin),engineer@resolutionflow.example.com(engineer),pro@resolutionflow.example.com(solo pro)
Critical Lessons Learned
Lessons 1-40 archived to
docs/LESSONS-ARCHIVE.md— fixes are baked into the codebase. Consult if you hit a regression.
Active Lessons (41+)
41. Assistant chat uses local React state, not Zustand: AssistantChatPage.tsx uses useState for chats, messages, input, loading. No store.
42. Public pages use raw fetch(), not apiClient: Survey, shared sessions, and no-auth pages use fetch() with full URL. apiClient requires auth tokens.
43. Adding new email types: Add static async method to EmailService in core/email.py. Fire-and-forget from endpoints (log errors, don't fail).
44. AI Chat Builder is flow-type-aware: ai_chat_service.py dispatches by flow_type. Troubleshooting: [TREE_UPDATE] markers. Procedural: [STEPS_UPDATE] markers. Both support [METADATA].
45. Intake form field schema: Uses variable_name and field_type (NOT name and type).
46. CreateFlowDropdown uses AIPromptDialog: Opens prompt modal, starts AI session, generates flow, navigates to editor with { state: { aiPanelOpen: true, sessionId } }.
47. Editor-Embedded Flow Assist: EditorAIPanel (320px side panel) + useEditorAI hook. Ghost nodes use _suggestion: true flag. Actions route to model tiers via settings.get_model_for_action(). Delta responses use [DELTA]...[/DELTA] markers.
48. Tree orphan validation uses dynamic root ID: Orphan check compares against state.treeStructure?.id (NOT hardcoded 'root').
49. Full-stack features — verify both ends: Check the full data flow: schema → endpoint → API client → hook → store → UI.
50. Anthropic SDK retry: Set max_retries=1 to fail fast. Default max_retries=2 can take 3× timeout.
51. AI model tier routing: Use settings.get_model_for_action(action_type). Model IDs: use alias form (claude-sonnet-4-6).
52. Mobile scroll-to-top: Use ref.current.scrollIntoView(), not window.scrollTo(). Trigger via useEffect.
53. Flex height chain: Every ancestor must be a flex container for flex-1 to work. Missing flex class collapses React Flow to 0 height.
54. React Flow CSS in Tailwind v4: Import in index.css, not component JS. Override dark theme using --xy-* CSS custom properties.
55. App shell height chain: Every wrapper between .main-content and canvas needs flex + flex-1 + min-h-0 or h-full.
56. Railway backend service name is patherly: Production DB name is railway. Public Postgres proxy: interchange.proxy.rlwy.net:45797.
57. Node field priority: title → question → description → content → label. See copilot_service.py.
58. scriptGeneratorStore.generate() optional param: Always wrap: onClick={() => generate()}, never onClick={generate}.
59. ConnectWise clientId is server-side config: Set in config.py as CW_CLIENT_ID. Per-connection: company_id, public_key, private_key, server_url.
60. Dockerfile build args for Vite env vars: Any new VITE_* or VITE_PUBLIC_* env var must be added as ARG + ENV in frontend/Dockerfile for Railway deploys. Railway env vars are runtime-only unless explicitly passed through as Docker build args. Without this, import.meta.env.VITE_* resolves to undefined in production builds.
61. Procedural sessions auto-start on page load: ProceduralNavigationPage calls startSession() immediately in loadTree() — there is no intake form screen or "Start" button. Variables are filled inline during execution. Troubleshooting flows DO have a start screen with ticket/client fields. Don't write tests or UI that assume a Start button on procedural flows.
62. Playwright strict mode — scope selectors to avoid ambiguity: Step titles appear in both the sidebar checklist and main content heading. Use getByRole('heading', { name }) for the main content, or scope with page.locator('.animate-scale-in') for command palette items. getByText() frequently matches multiple elements due to the sidebar + main content layout.
63. Node 20 required for frontend builds: Vite 7+ requires Node 20.19+. The system Node may be v18; use nvm: export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" && nvm use 20. For direct binary access without nvm sourcing: PATH="/home/michaelchihlas/.nvm/versions/node/v20.19.0/bin:$PATH".
64. PostHog product analytics: Initialized via PostHogProvider in main.tsx with explicit posthog.init() + client prop pattern. Event helpers in lib/analytics.ts — use analytics.eventName(props) to track. identifyUser() called in authStore.fetchUser(), resetAnalytics() on logout. Env vars: VITE_PUBLIC_POSTHOG_KEY, VITE_PUBLIC_POSTHOG_HOST. Autocapture enabled.
65. Local Docker Compose uses resolutionflow database on port 5433: Container name is resolutionflow_postgres, database is resolutionflow (not patherly), port mapped to 5433 (not 5432). The POSTGRES_PORT env var controls this. Playwright config defaults must match: postgresql+asyncpg://postgres:postgres@127.0.0.1:5433/resolutionflow.
66. Dev environment runs on devserver01 (192.168.0.9), not localhost: Code-server runs in Docker on a LAN server. Frontend/backend are accessed via 192.168.0.9, not localhost. CORS must include http://192.168.0.9:5173 in CORS_ORIGINS and FRONTEND_URL. Frontend .env must set VITE_API_URL=http://192.168.0.9:8000. See DEV-ENV.md for full setup, Docker config, networking, and known issues.
67. Tree editor route is /trees/new: NOT /editor/new. Check router.tsx line 156 for the canonical path. Use getTreeEditorPath() from @/lib/routing when navigating programmatically.
68. APScheduler jobs need max_instances=1: Without it, overlapping scheduler runs can process the same records twice (TOCTOU race). Always set max_instances=1 on interval jobs in main.py.
69. PostgreSQL func.sum(case(...)) returns Decimal via asyncpg: Cast to int() before storing in Pydantic dict[str, Any] fields, or JSON serialization may produce unexpected types.
70. Toast library uses toast.warning() not toast.warn(): Import from @/lib/toast. Methods: success, error, warning, info. See frontend/src/lib/toast.ts.
71. Enhancement/branch_addition proposals cannot be directly approved: Backend returns 400 — they require modified_flow_data via "Edit & Publish" flow. Only new_flow proposals support direct approve.
72. ai_sessions.status column is VARCHAR(30): Must fit requesting_escalation (23 chars). If adding new status values, verify length. Migration f0aad74ea51b widened from 20→30.
73. get_db rolls back on exception: The dependency does await session.rollback() on error to prevent InFailedSQLTransaction cascade. Never remove this — without it, one failed request poisons subsequent requests on the same connection.
74. FlowPilot action bar height chain: The action bar (Resolve/Escalate/Pause) requires every ancestor from app-shell grid down to have proper flex constraints. Key fix: ViewTransitionOutlet wrapper needs flex flex-col. If action bar disappears, check height chain with DevTools getBoundingClientRect() walk.
75. Dashboard prefill auto-submits: StartSessionInput navigates to /pilot or /assistant with { state: { prefill } }. FlowPilotSessionPage auto-submits via useEffect + prefillHandledRef guard — no double-enter. AssistantChatPage does the same pattern.
76. Active session navigation guard: FlowPilotSessionPage uses useBlocker (same as TreeEditorPage) to intercept navigation during active sessions. "Pause & Leave" auto-pauses before proceeding.
77. Prefer manual Alembic migrations for targeted changes: alembic revision --autogenerate picks up drift from all tables. For single-column fixes, use alembic revision -m "desc" and write op.alter_column() manually.
78. Landing page subtitle is "AI-Powered Troubleshooting for MSPs": Not "Decision Tree Platform". This tagline appears on login, register, and the HTML <title>. The old "Decision Tree Platform" was internal jargon misaligned with user-facing branding.
79. Custom modals must be mobile-responsive: Use items-end sm:items-center (bottom-sheet on mobile, centered on desktop) and max-w-full sm:max-w-lg (full-width on mobile). The shared Modal.tsx does this correctly — custom modal implementations must follow the same pattern. See PrepareSessionModal.tsx for the fix pattern.
80. TopBar search collapses to icon on mobile: Full search bar (hidden sm:block) shows on desktop; magnifying glass icon button (sm:hidden) shows on mobile (<640px). Both open the same CommandPalette. Don't add w-full search bar without the mobile icon fallback.
81. Never use transition: all in landing.css: Specify exact properties: transition: background 0.3s, border-color 0.3s, box-shadow 0.3s, transform 0.3s, opacity 0.3s. transition: all animates layout properties and causes jank.
82. bun requires PATH setup on devserver01: export BUN_INSTALL="$HOME/.bun" && export PATH="$BUN_INSTALL/bin:$PATH". The gstack browse binary and Playwright need this. Chromium system deps: libatk1.0-0 libatk-bridge2.0-0 libcups2 libxkbcommon0 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libasound2.
RBAC & Permissions
- Role hierarchy: super_admin > team_admin > engineer > viewer
- Team Admin:
role='engineer'+is_team_admin=True+ validteam_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"— useis_super_admininstead - Frontend:
usePermissions()hook for all permission checks - Centralized:
backend/app/core/permissions.py,frontend/src/hooks/usePermissions.ts
Design System (Slate & Ice Modern)
- Theme: Dark glassmorphism with ice-cyan accent (
#06b6d4→#22d3ee). Uses.glass-card/.glass-card-staticfor card surfaces - Backgrounds:
bg-background(#101114page), glass surfaces usergba(24, 26, 31, 0.55)withbackdrop-filter: blur() - Cards:
.glass-card(interactive, hoverscale(1.02)+ border/shadow upgrade) or.glass-card-static(no hover). Both haveborder-radius: 16px, semi-transparent bg, backdrop blur - Buttons: Primary:
bg-gradient-brand text-[#101114] font-semibold rounded-[10px] hover:opacity-90 active:scale-[0.97]. Secondary:bg-[rgba(255,255,255,0.04)] border-[rgba(255,255,255,0.06)] text-foreground rounded-[10px] - Inputs:
border-border bg-card text-foreground placeholder:text-muted-foreground+ focus:focus:border-[rgba(6,182,212,0.3)] - Text:
text-foreground(#f8fafc) →text-muted-foreground(#8891a0) →text-[#5a6170](dim, for section labels/timestamps) - Borders:
var(--glass-border)(rgba(255,255,255,0.06)) default,rgba(255,255,255,0.12)on hover - Hover states: Border brightens to
rgba(255,255,255,0.12), shadow upgrades to--shadow-float-hover - Active/selected:
bg-primary/10 text-foregroundor cyan gradient accent bar - Functional colors: emerald-400 (success), rose-500 (error), amber-400 (warning), blue-400 (info). Always pair with icons, not color alone.
- CSS variables: Glass system vars (
--glass-bg,--glass-border,--glass-blur), shadow system (--shadow-float,--shadow-float-hover,--shadow-cyan-glow), easing (--ease-out-smooth) — all inindex.css:root - Animations: Orchestrated page-load sequence (slideDown, slideInLeft, fadeInUp cascade, fadeInRight).
breatheGlowon first stat card.bellWobbleon notification hover. See design doc for full spec.
Frontend Patterns
- Component guidelines: Use
cn()from@/lib/utils, Lucide icons (wrap in<span>for title), modals with fixed header/footer - Type organization: Create in
types/, export fromtypes/index.ts, import withimport type { T } from '@/types' - Scratchpad overlay:
position: fixed,onOpenChangecallback for parent padding adjustment,right-2positioning - Custom step flow:
CustomStepModal→PostStepActionModal→ContinuationModal→ custom step view. Key state:pendingStep,pendingContinuationNodeId,customBranchMode,branchOriginNodeId. UsefindCustomStep()notfindNode()for custom step UUIDs. - Session sharing:
ShareSessionModalmanages share links,SharedSessionPagerenders public/account views. Helper utils inlib/sessionShare.ts. Share URLs use/shared/sessions/:token. - Procedural navigation:
ProceduralNavigationPagehandles intake forms, step-by-step execution, and resume vialocation.state.sessionId. UsesStepChecklist,StepDetail,ProgressBar,CompletionSummarycomponents. - Routing helper: Use
getTreeNavigatePath()andgetTreeEditorPath()from@/lib/routingfor all tree/session navigation. - Account section layout:
AccountLayouthas NO sidebar nav. Account sub-pages (categories, target-lists) are reached via link cards onAccountSettingsPage.tsx. New account pages: add route inrouter.tsxunderaccountchildren + add a link card inAccountSettingsPage. - Dashboard cockpit:
QuickStartPageis the FlowPilot launchpad. Components incomponents/dashboard/:StartSessionInput(mode picker: guided/chat),PendingEscalations,ActiveFlowPilotSessions,PerformanceCards,KnowledgeBaseCards,TeamSummary,RecentFlowPilotSessions. Every stat/card navigates to its detail page on click. - Sidebar sections: Dashboard → RESOLVE (Active Sessions, Escalations) → KNOWLEDGE (Flows, Step Library, Scripts, Review Queue) → INSIGHTS (Exports, Analytics, FlowPilot Analytics). Footer: User Guides, Feedback, Account, Collapse.
Common Tasks
- New endpoint: Create in
endpoints/→ add torouter.py→ schema inschemas/→ tests → frontend API client - New page: Create in
pages/→ add route inrouter.tsx→ nav link inAppLayout.tsx - New public route (no auth): Add at top level in
router.tsxalongside/login,/register— NOT inside theProtectedRoute/AppLayoutchildren. - Schema change: Update model →
alembic revision --autogenerate -m "desc"→ review →alembic upgrade head - New frontend API module: Types in
types/→ export fromtypes/index.ts→ client inapi/→ export fromapi/index.ts
Coding Standards
Python
- Type hints everywhere, async/await for DB, Pydantic for validation,
DateTime(timezone=True)always
TypeScript
- Interfaces for all data,
constoverlet, 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 <noreply@anthropic.com> - Always create feature branch BEFORE committing:
git checkout -b feat/feature-name - Large features: commit per phase with
npm run buildvalidation
After Completing Work
When a feature, fix, or significant piece of work is finished and merged/committed:
- Update
CURRENT-STATE.md— move completed items, update "In Progress" and "What's Next" sections - Update
03-DEVELOPMENT-ROADMAP.md— check off completed work, update phase status - Close related GitHub Issues — use
gh issue close #Nfor any issues resolved by the work - Update
CLAUDE.mdif the work introduced new patterns, lessons learned, or changed project structure
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_URLset withhttps://prefix on frontend service ALLOW_RAILWAY_ORIGINS=trueenables CORS for*.up.railway.app- Shared Variables (project-level in Railway dashboard) auto-propagate to all environments including PR envs — use for secrets like
ANTHROPIC_API_KEY - Super admin utility:
backend/make_superadmin_simple.py list|<email>
gstack
Use /browse from gstack for all web browsing — never use mcp__claude-in-chrome__* tools.
Available skills: /office-hours, /plan-ceo-review, /plan-eng-review, /plan-design-review, /design-consultation, /review, /ship, /browse, /qa, /qa-only, /design-review, /setup-browser-cookies, /retro, /investigate, /document-release, /codex, /careful, /freeze, /guard, /unfreeze, /gstack-upgrade
Future Roadmap
- Phase 3: PSA integrations (ConnectWise in progress), file attachments, client context, analytics
- Phase 4: Additional PSA integrations (Autotask/Kaseya), PowerShell automation, enterprise SSO
Quick Reference
| What | Where |
|---|---|
| API Docs | http://localhost:8000/api/docs |
| Detailed Status | CURRENT-STATE.md |
| Development Roadmap | 03-DEVELOPMENT-ROADMAP.md |
| GitHub Issues | gh issue list --state open |
| Bugs & Fixes | CLAUDE.md → Critical Lessons Learned section |
| Feature Specs | 04-FEATURE-SPECIFICATIONS.md |
| Design System | docs/plans/Frontend/DESIGN_SYSTEM_GUIDE.md |
| Dev Environment | DEV-ENV.md — devserver01 setup, Docker, CORS, networking |