docs: Improve CLAUDE.md with claude-md-improver skill

- Add Environment Variables section with backend/.env and frontend config
- Update Development Commands to use relative paths (cross-platform)
- Add Frontend Operations section (build, preview, lint)
- Enhance Run Tests with first-time setup instructions
- Condense API Endpoints Reference (~85 lines saved, link to OpenAPI docs)
- Add Git Patterns section documenting .gitignore requirements
- Update all commands to work from project root
- Add Windows/Linux/Mac compatibility notes for venv activation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Michael Chihlas
2026-02-03 14:51:15 -05:00
parent d1201cc584
commit 9dd84a0907

336
CLAUDE.md
View File

@@ -1,7 +1,7 @@
# CLAUDE.md - Patherly Project Context
> **Purpose:** This file provides Claude Code with essential context for working on the Patherly project.
> **Last Updated:** February 3, 2026
> **Last Updated:** February 3, 2026 (improved by claude-md-improver)
---
@@ -25,6 +25,7 @@
- **Database:** PostgreSQL with Docker (container name: `patherly_postgres`)
### What's Complete
- User authentication (JWT, register, login, refresh, invite codes)
- Trees CRUD with full-text search
- Sessions tracking with decisions
@@ -63,9 +64,11 @@
- Rating/review system with verified use tracking
### What's In Progress
- Step Library frontend UI (Phase 2.5 continuation)
### Deployment
- **Production:** Railway (app.patherly.com / api.patherly.com)
- **PR Environments:** Enabled - auto-created for each pull request
@@ -74,6 +77,7 @@
## Tech Stack
### Backend
- **Framework:** Python FastAPI
- **Database:** PostgreSQL 16 (async via SQLAlchemy 2.0 + asyncpg)
- **Migrations:** Alembic
@@ -81,6 +85,7 @@
- **Validation:** Pydantic v2
### Frontend
- **Framework:** React 19 + Vite + TypeScript
- **Styling:** Tailwind CSS v3
- **State:** Zustand (with immer + zundo for undo/redo)
@@ -183,6 +188,42 @@ patherly/
---
## Environment Variables
### Backend (.env)
**Required in `backend/.env`:**
```bash
# Application
APP_NAME=Patherly
DEBUG=true # Set false in production
# Database (matches docker-compose.yml)
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/patherly
DATABASE_URL_SYNC=postgresql://postgres:postgres@localhost:5432/patherly
# JWT Settings - CHANGE THESE IN PRODUCTION
SECRET_KEY=<generate with: openssl rand -hex 32>
ACCESS_TOKEN_EXPIRE_MINUTES=30
REFRESH_TOKEN_EXPIRE_MINUTES=10080
# Auth
REQUIRE_INVITE_CODE=true # Set false to allow open registration
```
**Railway-specific (production):**
```bash
ALLOW_RAILWAY_ORIGINS=true # Enables CORS for PR environments
```
### Frontend (.env.local - optional)
```bash
VITE_API_URL=http://localhost:8000 # Override API URL
```
---
## Development Commands
### Start Development Environment
@@ -191,40 +232,73 @@ patherly/
# Terminal 1: Start PostgreSQL
docker start patherly_postgres
# Terminal 2: Backend
cd C:\Dev\Projects\patherly\patherly\backend
# Terminal 2: Backend (from project root)
cd backend
# Windows:
.\venv\Scripts\Activate
# Linux/Mac:
source venv/bin/activate
uvicorn app.main:app --reload
# Terminal 3: Frontend
cd C:\Dev\Projects\patherly\patherly\frontend
# Terminal 3: Frontend (from project root)
cd frontend
npm run dev
```
### URLs
- Frontend: http://localhost:5173
- Backend API: http://localhost:8000
- API Docs: http://localhost:8000/api/docs
### Run Tests
```powershell
cd C:\Dev\Projects\patherly\patherly\backend
.\venv\Scripts\Activate
# From project root
cd backend
# First time only: create test database
docker exec -it patherly_postgres psql -U postgres -c "CREATE DATABASE patherly_test;"
# Install test dependencies (if not already installed)
pip install -r requirements-dev.txt
# Run tests
pytest
```
### Run Seed Scripts
### Frontend Operations
```powershell
cd C:\Dev\Projects\patherly\patherly\backend
.\venv\Scripts\Activate
# From project root
cd frontend
# Build for production
npm run build
# Preview production build
npm run preview
# Lint code
npm run lint
```
### Run Seed Scripts
```powershell
# From project root
cd backend
pip install httpx # Required for seed scripts
python -m scripts.seed_trees
```
### Database Operations
```powershell
# Run migrations
# From project root
cd backend
# Run migrations
alembic upgrade head
# Create new migration
@@ -241,6 +315,7 @@ docker exec -it patherly_postgres psql -U postgres -d patherly
**ALWAYS read [LESSONS-LEARNED.md](LESSONS-LEARNED.md) before making changes!**
### DateTime Handling (Critical)
```python
# CORRECT - Always use timezone-aware datetimes
from datetime import datetime, timezone
@@ -253,6 +328,7 @@ datetime.utcnow() # Deprecated, returns naive datetime
```
### React State: Don't Store Object Snapshots
```tsx
// WRONG - Snapshot won't update when store changes
const [editingNode, setEditingNode] = useState<TreeStructure | null>(null)
@@ -263,6 +339,7 @@ const editingNode = editingNodeId ? findNode(editingNodeId) : null
```
### Modal Draft State: Don't Overwrite Store-Managed Fields
```tsx
// WRONG - Overwrites children with stale snapshot
const handleSave = () => {
@@ -277,14 +354,17 @@ const handleSave = () => {
```
### Database Name
- Database name is `patherly` (not `decision_tree`)
- Update `.env` if you see the old name
### Virtual Environment
- Always check for `(venv)` prefix before running pip
- Don't use `--break-system-packages` when venv is active
### PostgreSQL NULL Casting for UUID Columns
```sql
-- WRONG - PostgreSQL infers NULL as text type
INSERT INTO tree_tags (name, slug, team_id)
@@ -297,6 +377,7 @@ SELECT 'tag', 'slug', NULL::uuid as team_id -- Works!
Always use `NULL::uuid` when inserting NULL values into UUID columns in raw SQL.
### SQLAlchemy Async: Avoid Lazy Loading on New Objects
```python
# WRONG - Triggers lazy load which fails in async context
new_tree = Tree(...)
@@ -316,6 +397,7 @@ await db.execute(
Accessing relationships on newly created objects triggers lazy loading, which fails in async SQLAlchemy. Use direct SQL inserts for junction tables instead.
### React Router: Clear Dirty State Before Navigation
```tsx
// WRONG - Navigation triggers before dirty flag is cleared
const newTree = await treesApi.create(data)
@@ -329,118 +411,58 @@ navigate(`/trees/${newTree.id}/edit`) // Blocker won't fire
```
When using `useBlocker` for unsaved changes, always clear the dirty flag before programmatic navigation.
### CORS: Include Both allow_origins AND allow_origin_regex
```python
# WRONG - Custom domains ignored when using regex
if settings.ALLOW_RAILWAY_ORIGINS:
app.add_middleware(
CORSMiddleware,
allow_origin_regex=r"https://.*\.up\.railway\.app", # Only matches Railway domains!
# ...
)
# CORRECT - Include both for custom domains + Railway PR environments
if settings.ALLOW_RAILWAY_ORIGINS:
app.add_middleware(
CORSMiddleware,
allow_origins=settings.allowed_origins, # Custom domains like app.patherly.com
allow_origin_regex=r"https://.*\.up\.railway\.app", # Railway PR domains
# ...
)
```
When using `allow_origin_regex` for wildcard patterns, also include `allow_origins` for explicit custom domains. The regex alone won't match custom domains like `app.patherly.com`.
---
## API Endpoints Reference
### Authentication
```
POST /api/v1/auth/register - Register (requires invite code by default)
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
```
**Full API documentation:** http://localhost:8000/api/docs (interactive OpenAPI/Swagger UI)
### Trees
```
GET /api/v1/trees - List trees (filters: category_id, tags, folder_id)
POST /api/v1/trees - Create tree (supports tags, category_id)
GET /api/v1/trees/categories - Get legacy string categories
GET /api/v1/trees/search - Full-text search
GET /api/v1/trees/{id} - Get tree (includes tags, category_info)
PUT /api/v1/trees/{id} - Update tree
DELETE /api/v1/trees/{id} - Soft delete
```
**Quick reference:**
- **Auth:** `/api/v1/auth/*` - register, login, refresh, logout, me
- **Trees:** `/api/v1/trees/*` - CRUD, search, categories (supports filters: category_id, tags, folder_id)
- **Sessions:** `/api/v1/sessions/*` - start, track, complete, export (markdown/text/html)
- **Tags:** `/api/v1/tags/*` - manage tree tags, autocomplete search
- **Folders:** `/api/v1/folders/*` - user folders with subfolder hierarchy (max 3 levels deep)
- **Categories:** `/api/v1/categories/*` - tree categories (global + team-specific)
- **Step Categories:** `/api/v1/step-categories/*` - step categories for library
- **Step Library:** `/api/v1/steps/*` - reusable steps, ratings, reviews, full-text search
- **Invite Codes:** `/api/v1/invite-codes/*` - admin management
### Categories (NEW)
```
GET /api/v1/categories - List categories (global + user's team)
POST /api/v1/categories - Create category (team/global admin)
GET /api/v1/categories/{id} - Get category
PUT /api/v1/categories/{id} - Update category
DELETE /api/v1/categories/{id} - Soft delete category
```
**Key constraints:**
- Folder hierarchy: max 3 levels deep (root → child → grandchild)
- Step ratings: 1-5 stars with optional review text
- Categories and tags: support both global and team-specific scoping
### Tags (NEW)
```
GET /api/v1/tags - List tags (global + user's team)
GET /api/v1/tags/search - Autocomplete search
POST /api/v1/tags - Create tag
GET /api/v1/tags/{id} - Get tag
GET /api/v1/tags/trees/{id} - Get tree's tags
POST /api/v1/tags/trees/{id} - Add tags to tree
PUT /api/v1/tags/trees/{id} - Replace tree's tags
DELETE /api/v1/tags/trees/{id}/{slug} - Remove tag from tree
```
### Folders
```
GET /api/v1/folders - List user's folders (includes parent_id)
POST /api/v1/folders - Create folder (supports parent_id for subfolders)
GET /api/v1/folders/{id} - Get folder
PUT /api/v1/folders/{id} - Update folder (supports moving via parent_id)
DELETE /api/v1/folders/{id} - Delete folder (cascades to subfolders)
POST /api/v1/folders/reorder - Reorder folders
POST /api/v1/folders/{id}/trees - Add tree to folder
GET /api/v1/folders/{id}/trees - Get folder's tree IDs
DELETE /api/v1/folders/{id}/trees/{tree_id} - Remove tree from folder
```
**Folder hierarchy constraints:**
- Max nesting depth: 3 levels (root → child → grandchild)
- Same folder name allowed under different parents
- Moving folders validates cycle prevention
### Step Categories (NEW)
```
GET /api/v1/step-categories - List categories (global + user's team)
POST /api/v1/step-categories - Create category (admin/team_admin)
GET /api/v1/step-categories/{id} - Get category
PUT /api/v1/step-categories/{id} - Update category
DELETE /api/v1/step-categories/{id} - Soft delete category
```
### Step Library (NEW)
```
GET /api/v1/steps - List steps (filters: visibility, category_id, tags, min_rating, step_type, sort_by)
POST /api/v1/steps - Create step
GET /api/v1/steps/{id} - Get step details
PUT /api/v1/steps/{id} - Update step (owner/admin)
DELETE /api/v1/steps/{id} - Soft delete step (owner/admin)
GET /api/v1/steps/search - Full-text search (?q=query)
GET /api/v1/steps/tags/popular - Popular tags list
# Rating endpoints
POST /api/v1/steps/{id}/rate - Rate a step (1-5 stars + optional review)
PUT /api/v1/steps/{id}/rate - Update your rating
DELETE /api/v1/steps/{id}/rate - Remove your rating
GET /api/v1/steps/{id}/reviews - Get reviews for a step
```
### Sessions
```
GET /api/v1/sessions - List user's sessions
POST /api/v1/sessions - Start session
GET /api/v1/sessions/{id} - Get session
PUT /api/v1/sessions/{id} - Update session
POST /api/v1/sessions/{id}/complete - Complete session
POST /api/v1/sessions/{id}/export - Export (md/txt/html)
```
### Invite Codes
```
GET /api/v1/invite-codes - List codes (admin)
POST /api/v1/invite-codes - Create code (admin)
GET /api/v1/invite-codes/validate/{code} - Validate code
```
For detailed parameters, request/response schemas, and examples, visit the API docs.
---
## Data Models
### Tree Structure (JSONB)
```typescript
interface TreeStructure {
id: string
@@ -472,6 +494,7 @@ interface TreeStructure {
```
### Session Decisions (JSONB)
```typescript
interface Decision {
node_id: string
@@ -487,18 +510,21 @@ interface Decision {
## Frontend Patterns
### State Management
- **Auth:** `useAuthStore` - Zustand with localStorage persistence
- **Theme:** `useThemeStore` - Dark/light/system preference
- **Tree Editor:** `useTreeEditorStore` - Zustand + immer + zundo (undo/redo)
- **User Preferences:** `useUserPreferencesStore` - Zustand with localStorage persistence (export format default)
### Component Guidelines
- Use `cn()` from `@/lib/utils` for Tailwind class merging
- Use Lucide icons (no `title` prop - wrap in `<span>` instead)
- Modals: Use fixed header/footer with scrollable body
- Forms: Show field-level validation errors
### API Client Pattern
```typescript
import api from '@/api/client'
@@ -536,6 +562,7 @@ const response = await api.get('/api/v1/trees')
## Coding Standards
### Python (Backend)
- Use type hints everywhere
- Use async/await for database operations
- Use Pydantic for validation
@@ -543,6 +570,7 @@ const response = await api.get('/api/v1/trees')
- Always use `DateTime(timezone=True)` for timestamps
### TypeScript (Frontend)
- Enable strict mode (when ready)
- Use TypeScript interfaces for all data structures
- Prefer `const` over `let`
@@ -550,6 +578,7 @@ const response = await api.get('/api/v1/trees')
- Extract reusable logic into custom hooks
### Git
- Commit message format: `type: description`
- Types: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`
- Always include `Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>`
@@ -559,6 +588,7 @@ const response = await api.get('/api/v1/trees')
## Future Roadmap
### Phase 2.5 (In Progress)
- ✅ Step Categories database and API
- ✅ Step Library database schema (step_library, step_ratings, step_usage_log)
- ✅ Step Library CRUD API with search and ratings
@@ -570,12 +600,14 @@ const response = await api.get('/api/v1/trees')
- 🔲 Tree forking and sharing
### Phase 3 (Planned)
- File attachments (screenshots, logs)
- Offline mode (Service Workers + IndexedDB)
- Client context system
- Analytics dashboard
### Phase 4 (Planned)
- API & integrations (ConnectWise, Kaseya)
- PowerShell automation execution
- Enterprise features (SSO, white-labeling)
@@ -585,25 +617,59 @@ const response = await api.get('/api/v1/trees')
## Troubleshooting
### Backend won't start
1. Check Docker: `docker ps` - is `patherly_postgres` running?
2. Check `.env` - is DATABASE_URL correct (`patherly` not `decision_tree`)?
3. Check venv: is `(venv)` prefix showing?
### Frontend compile errors
1. Check `frontend/src/lib/utils.ts` exists (provides `cn()` function)
2. Run `npm install` to ensure dependencies are installed
### Tests failing
1. Create test database: `docker exec -it patherly_postgres psql -U postgres -c "CREATE DATABASE patherly_test;"`
2. Install dev deps: `pip install -r requirements-dev.txt`
3. Ensure pytest-asyncio version: `pip install pytest-asyncio==0.24.0`
### API 500 errors
1. Check server logs for datetime errors (timezone issue)
2. Ensure all datetimes use `datetime.now(timezone.utc)`
---
## Git Patterns
**Always gitignore:**
```
# Secrets and local config
backend/.env
.claude.local.md
# Dependencies
backend/venv/
frontend/node_modules/
# Build artifacts
frontend/dist/
backend/**/__pycache__/
*.pyc
# Railway CLI (local tooling only)
/node_modules/
/package.json
/package-lock.json
# IDE
.vscode/
.idea/
*.swp
```
---
## Quick Reference
| What | Where |
@@ -619,12 +685,14 @@ const response = await api.get('/api/v1/trees')
## Railway Deployment
### Production
- **Frontend:** https://app.patherly.com
- **Backend:** https://api.patherly.com
- **Database:** Railway-managed PostgreSQL
- Deploys automatically on push to `main`
### PR Environments
Railway creates isolated preview environments for each pull request.
**Workflow:**
@@ -656,6 +724,54 @@ Railway creates isolated preview environments for each pull request.
**Debug Endpoints (available in PR environments):**
- `/debug/cors` - Check CORS configuration (allow_railway_origins, cors_mode)
### Railway CLI (Local)
The Railway CLI can be installed locally for managing deployments, viewing logs, and checking service status.
**Setup on a new machine:**
```powershell
# 1. Install Railway CLI via npm (in project root)
cd C:\Dev\Projects\patherly
npm init -y
npm install @railway/cli
# 2. Login to Railway
./node_modules/.bin/railway login
# 3. Link to the project
./node_modules/.bin/railway link
# Select: selfless-grace → production
```
**Common Commands:**
```powershell
# Check service status
./node_modules/.bin/railway service status --service patherly
./node_modules/.bin/railway service status --all
# View logs
./node_modules/.bin/railway service logs --service patherly
# Check environment variables
./node_modules/.bin/railway variables --service patherly
# Deploy new code (from backend directory)
cd backend && ../node_modules/.bin/railway up --service patherly
# Redeploy existing build
./node_modules/.bin/railway service redeploy --service patherly --yes
```
**Services:**
- `patherly` - Backend API
- `hopeful-liberation` - Frontend
- `Postgres` - Database
**Note:** The `node_modules/`, `package.json`, and `package-lock.json` files for the Railway CLI are gitignored (local tooling only).
---
## Contact