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:
336
CLAUDE.md
336
CLAUDE.md
@@ -1,7 +1,7 @@
|
|||||||
# CLAUDE.md - Patherly Project Context
|
# CLAUDE.md - Patherly Project Context
|
||||||
|
|
||||||
> **Purpose:** This file provides Claude Code with essential context for working on the Patherly project.
|
> **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`)
|
- **Database:** PostgreSQL with Docker (container name: `patherly_postgres`)
|
||||||
|
|
||||||
### What's Complete
|
### What's Complete
|
||||||
|
|
||||||
- User authentication (JWT, register, login, refresh, invite codes)
|
- User authentication (JWT, register, login, refresh, invite codes)
|
||||||
- Trees CRUD with full-text search
|
- Trees CRUD with full-text search
|
||||||
- Sessions tracking with decisions
|
- Sessions tracking with decisions
|
||||||
@@ -63,9 +64,11 @@
|
|||||||
- Rating/review system with verified use tracking
|
- Rating/review system with verified use tracking
|
||||||
|
|
||||||
### What's In Progress
|
### What's In Progress
|
||||||
|
|
||||||
- Step Library frontend UI (Phase 2.5 continuation)
|
- Step Library frontend UI (Phase 2.5 continuation)
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
|
|
||||||
- **Production:** Railway (app.patherly.com / api.patherly.com)
|
- **Production:** Railway (app.patherly.com / api.patherly.com)
|
||||||
- **PR Environments:** Enabled - auto-created for each pull request
|
- **PR Environments:** Enabled - auto-created for each pull request
|
||||||
|
|
||||||
@@ -74,6 +77,7 @@
|
|||||||
## Tech Stack
|
## Tech Stack
|
||||||
|
|
||||||
### Backend
|
### Backend
|
||||||
|
|
||||||
- **Framework:** Python FastAPI
|
- **Framework:** Python FastAPI
|
||||||
- **Database:** PostgreSQL 16 (async via SQLAlchemy 2.0 + asyncpg)
|
- **Database:** PostgreSQL 16 (async via SQLAlchemy 2.0 + asyncpg)
|
||||||
- **Migrations:** Alembic
|
- **Migrations:** Alembic
|
||||||
@@ -81,6 +85,7 @@
|
|||||||
- **Validation:** Pydantic v2
|
- **Validation:** Pydantic v2
|
||||||
|
|
||||||
### Frontend
|
### Frontend
|
||||||
|
|
||||||
- **Framework:** React 19 + Vite + TypeScript
|
- **Framework:** React 19 + Vite + TypeScript
|
||||||
- **Styling:** Tailwind CSS v3
|
- **Styling:** Tailwind CSS v3
|
||||||
- **State:** Zustand (with immer + zundo for undo/redo)
|
- **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
|
## Development Commands
|
||||||
|
|
||||||
### Start Development Environment
|
### Start Development Environment
|
||||||
@@ -191,40 +232,73 @@ patherly/
|
|||||||
# Terminal 1: Start PostgreSQL
|
# Terminal 1: Start PostgreSQL
|
||||||
docker start patherly_postgres
|
docker start patherly_postgres
|
||||||
|
|
||||||
# Terminal 2: Backend
|
# Terminal 2: Backend (from project root)
|
||||||
cd C:\Dev\Projects\patherly\patherly\backend
|
cd backend
|
||||||
|
# Windows:
|
||||||
.\venv\Scripts\Activate
|
.\venv\Scripts\Activate
|
||||||
|
# Linux/Mac:
|
||||||
|
source venv/bin/activate
|
||||||
uvicorn app.main:app --reload
|
uvicorn app.main:app --reload
|
||||||
|
|
||||||
# Terminal 3: Frontend
|
# Terminal 3: Frontend (from project root)
|
||||||
cd C:\Dev\Projects\patherly\patherly\frontend
|
cd frontend
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### URLs
|
### URLs
|
||||||
|
|
||||||
- Frontend: http://localhost:5173
|
- Frontend: http://localhost:5173
|
||||||
- Backend API: http://localhost:8000
|
- Backend API: http://localhost:8000
|
||||||
- API Docs: http://localhost:8000/api/docs
|
- API Docs: http://localhost:8000/api/docs
|
||||||
|
|
||||||
### Run Tests
|
### Run Tests
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
cd C:\Dev\Projects\patherly\patherly\backend
|
# From project root
|
||||||
.\venv\Scripts\Activate
|
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
|
pytest
|
||||||
```
|
```
|
||||||
|
|
||||||
### Run Seed Scripts
|
### Frontend Operations
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
cd C:\Dev\Projects\patherly\patherly\backend
|
# From project root
|
||||||
.\venv\Scripts\Activate
|
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
|
pip install httpx # Required for seed scripts
|
||||||
python -m scripts.seed_trees
|
python -m scripts.seed_trees
|
||||||
```
|
```
|
||||||
|
|
||||||
### Database Operations
|
### Database Operations
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# Run migrations
|
# From project root
|
||||||
cd backend
|
cd backend
|
||||||
|
|
||||||
|
# Run migrations
|
||||||
alembic upgrade head
|
alembic upgrade head
|
||||||
|
|
||||||
# Create new migration
|
# 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!**
|
**ALWAYS read [LESSONS-LEARNED.md](LESSONS-LEARNED.md) before making changes!**
|
||||||
|
|
||||||
### DateTime Handling (Critical)
|
### DateTime Handling (Critical)
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# CORRECT - Always use timezone-aware datetimes
|
# CORRECT - Always use timezone-aware datetimes
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
@@ -253,6 +328,7 @@ datetime.utcnow() # Deprecated, returns naive datetime
|
|||||||
```
|
```
|
||||||
|
|
||||||
### React State: Don't Store Object Snapshots
|
### React State: Don't Store Object Snapshots
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// WRONG - Snapshot won't update when store changes
|
// WRONG - Snapshot won't update when store changes
|
||||||
const [editingNode, setEditingNode] = useState<TreeStructure | null>(null)
|
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
|
### Modal Draft State: Don't Overwrite Store-Managed Fields
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// WRONG - Overwrites children with stale snapshot
|
// WRONG - Overwrites children with stale snapshot
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
@@ -277,14 +354,17 @@ const handleSave = () => {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Database Name
|
### Database Name
|
||||||
|
|
||||||
- Database name is `patherly` (not `decision_tree`)
|
- Database name is `patherly` (not `decision_tree`)
|
||||||
- Update `.env` if you see the old name
|
- Update `.env` if you see the old name
|
||||||
|
|
||||||
### Virtual Environment
|
### Virtual Environment
|
||||||
|
|
||||||
- Always check for `(venv)` prefix before running pip
|
- Always check for `(venv)` prefix before running pip
|
||||||
- Don't use `--break-system-packages` when venv is active
|
- Don't use `--break-system-packages` when venv is active
|
||||||
|
|
||||||
### PostgreSQL NULL Casting for UUID Columns
|
### PostgreSQL NULL Casting for UUID Columns
|
||||||
|
|
||||||
```sql
|
```sql
|
||||||
-- WRONG - PostgreSQL infers NULL as text type
|
-- WRONG - PostgreSQL infers NULL as text type
|
||||||
INSERT INTO tree_tags (name, slug, team_id)
|
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.
|
Always use `NULL::uuid` when inserting NULL values into UUID columns in raw SQL.
|
||||||
|
|
||||||
### SQLAlchemy Async: Avoid Lazy Loading on New Objects
|
### SQLAlchemy Async: Avoid Lazy Loading on New Objects
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# WRONG - Triggers lazy load which fails in async context
|
# WRONG - Triggers lazy load which fails in async context
|
||||||
new_tree = Tree(...)
|
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.
|
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
|
### React Router: Clear Dirty State Before Navigation
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
// WRONG - Navigation triggers before dirty flag is cleared
|
// WRONG - Navigation triggers before dirty flag is cleared
|
||||||
const newTree = await treesApi.create(data)
|
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.
|
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
|
## API Endpoints Reference
|
||||||
|
|
||||||
### Authentication
|
**Full API documentation:** http://localhost:8000/api/docs (interactive OpenAPI/Swagger UI)
|
||||||
```
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
### Trees
|
**Quick reference:**
|
||||||
```
|
- **Auth:** `/api/v1/auth/*` - register, login, refresh, logout, me
|
||||||
GET /api/v1/trees - List trees (filters: category_id, tags, folder_id)
|
- **Trees:** `/api/v1/trees/*` - CRUD, search, categories (supports filters: category_id, tags, folder_id)
|
||||||
POST /api/v1/trees - Create tree (supports tags, category_id)
|
- **Sessions:** `/api/v1/sessions/*` - start, track, complete, export (markdown/text/html)
|
||||||
GET /api/v1/trees/categories - Get legacy string categories
|
- **Tags:** `/api/v1/tags/*` - manage tree tags, autocomplete search
|
||||||
GET /api/v1/trees/search - Full-text search
|
- **Folders:** `/api/v1/folders/*` - user folders with subfolder hierarchy (max 3 levels deep)
|
||||||
GET /api/v1/trees/{id} - Get tree (includes tags, category_info)
|
- **Categories:** `/api/v1/categories/*` - tree categories (global + team-specific)
|
||||||
PUT /api/v1/trees/{id} - Update tree
|
- **Step Categories:** `/api/v1/step-categories/*` - step categories for library
|
||||||
DELETE /api/v1/trees/{id} - Soft delete
|
- **Step Library:** `/api/v1/steps/*` - reusable steps, ratings, reviews, full-text search
|
||||||
```
|
- **Invite Codes:** `/api/v1/invite-codes/*` - admin management
|
||||||
|
|
||||||
### Categories (NEW)
|
**Key constraints:**
|
||||||
```
|
- Folder hierarchy: max 3 levels deep (root → child → grandchild)
|
||||||
GET /api/v1/categories - List categories (global + user's team)
|
- Step ratings: 1-5 stars with optional review text
|
||||||
POST /api/v1/categories - Create category (team/global admin)
|
- Categories and tags: support both global and team-specific scoping
|
||||||
GET /api/v1/categories/{id} - Get category
|
|
||||||
PUT /api/v1/categories/{id} - Update category
|
|
||||||
DELETE /api/v1/categories/{id} - Soft delete category
|
|
||||||
```
|
|
||||||
|
|
||||||
### Tags (NEW)
|
For detailed parameters, request/response schemas, and examples, visit the API docs.
|
||||||
```
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Data Models
|
## Data Models
|
||||||
|
|
||||||
### Tree Structure (JSONB)
|
### Tree Structure (JSONB)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface TreeStructure {
|
interface TreeStructure {
|
||||||
id: string
|
id: string
|
||||||
@@ -472,6 +494,7 @@ interface TreeStructure {
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Session Decisions (JSONB)
|
### Session Decisions (JSONB)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
interface Decision {
|
interface Decision {
|
||||||
node_id: string
|
node_id: string
|
||||||
@@ -487,18 +510,21 @@ interface Decision {
|
|||||||
## Frontend Patterns
|
## Frontend Patterns
|
||||||
|
|
||||||
### State Management
|
### State Management
|
||||||
|
|
||||||
- **Auth:** `useAuthStore` - Zustand with localStorage persistence
|
- **Auth:** `useAuthStore` - Zustand with localStorage persistence
|
||||||
- **Theme:** `useThemeStore` - Dark/light/system preference
|
- **Theme:** `useThemeStore` - Dark/light/system preference
|
||||||
- **Tree Editor:** `useTreeEditorStore` - Zustand + immer + zundo (undo/redo)
|
- **Tree Editor:** `useTreeEditorStore` - Zustand + immer + zundo (undo/redo)
|
||||||
- **User Preferences:** `useUserPreferencesStore` - Zustand with localStorage persistence (export format default)
|
- **User Preferences:** `useUserPreferencesStore` - Zustand with localStorage persistence (export format default)
|
||||||
|
|
||||||
### Component Guidelines
|
### Component Guidelines
|
||||||
|
|
||||||
- Use `cn()` from `@/lib/utils` for Tailwind class merging
|
- Use `cn()` from `@/lib/utils` for Tailwind class merging
|
||||||
- Use Lucide icons (no `title` prop - wrap in `<span>` instead)
|
- Use Lucide icons (no `title` prop - wrap in `<span>` instead)
|
||||||
- Modals: Use fixed header/footer with scrollable body
|
- Modals: Use fixed header/footer with scrollable body
|
||||||
- Forms: Show field-level validation errors
|
- Forms: Show field-level validation errors
|
||||||
|
|
||||||
### API Client Pattern
|
### API Client Pattern
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import api from '@/api/client'
|
import api from '@/api/client'
|
||||||
|
|
||||||
@@ -536,6 +562,7 @@ const response = await api.get('/api/v1/trees')
|
|||||||
## Coding Standards
|
## Coding Standards
|
||||||
|
|
||||||
### Python (Backend)
|
### Python (Backend)
|
||||||
|
|
||||||
- Use type hints everywhere
|
- Use type hints everywhere
|
||||||
- Use async/await for database operations
|
- Use async/await for database operations
|
||||||
- Use Pydantic for validation
|
- Use Pydantic for validation
|
||||||
@@ -543,6 +570,7 @@ const response = await api.get('/api/v1/trees')
|
|||||||
- Always use `DateTime(timezone=True)` for timestamps
|
- Always use `DateTime(timezone=True)` for timestamps
|
||||||
|
|
||||||
### TypeScript (Frontend)
|
### TypeScript (Frontend)
|
||||||
|
|
||||||
- Enable strict mode (when ready)
|
- Enable strict mode (when ready)
|
||||||
- Use TypeScript interfaces for all data structures
|
- Use TypeScript interfaces for all data structures
|
||||||
- Prefer `const` over `let`
|
- Prefer `const` over `let`
|
||||||
@@ -550,6 +578,7 @@ const response = await api.get('/api/v1/trees')
|
|||||||
- Extract reusable logic into custom hooks
|
- Extract reusable logic into custom hooks
|
||||||
|
|
||||||
### Git
|
### Git
|
||||||
|
|
||||||
- Commit message format: `type: description`
|
- Commit message format: `type: description`
|
||||||
- Types: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`
|
- Types: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`
|
||||||
- Always include `Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>`
|
- 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
|
## Future Roadmap
|
||||||
|
|
||||||
### Phase 2.5 (In Progress)
|
### Phase 2.5 (In Progress)
|
||||||
|
|
||||||
- ✅ Step Categories database and API
|
- ✅ Step Categories database and API
|
||||||
- ✅ Step Library database schema (step_library, step_ratings, step_usage_log)
|
- ✅ Step Library database schema (step_library, step_ratings, step_usage_log)
|
||||||
- ✅ Step Library CRUD API with search and ratings
|
- ✅ Step Library CRUD API with search and ratings
|
||||||
@@ -570,12 +600,14 @@ const response = await api.get('/api/v1/trees')
|
|||||||
- 🔲 Tree forking and sharing
|
- 🔲 Tree forking and sharing
|
||||||
|
|
||||||
### Phase 3 (Planned)
|
### Phase 3 (Planned)
|
||||||
|
|
||||||
- File attachments (screenshots, logs)
|
- File attachments (screenshots, logs)
|
||||||
- Offline mode (Service Workers + IndexedDB)
|
- Offline mode (Service Workers + IndexedDB)
|
||||||
- Client context system
|
- Client context system
|
||||||
- Analytics dashboard
|
- Analytics dashboard
|
||||||
|
|
||||||
### Phase 4 (Planned)
|
### Phase 4 (Planned)
|
||||||
|
|
||||||
- API & integrations (ConnectWise, Kaseya)
|
- API & integrations (ConnectWise, Kaseya)
|
||||||
- PowerShell automation execution
|
- PowerShell automation execution
|
||||||
- Enterprise features (SSO, white-labeling)
|
- Enterprise features (SSO, white-labeling)
|
||||||
@@ -585,25 +617,59 @@ const response = await api.get('/api/v1/trees')
|
|||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Backend won't start
|
### Backend won't start
|
||||||
|
|
||||||
1. Check Docker: `docker ps` - is `patherly_postgres` running?
|
1. Check Docker: `docker ps` - is `patherly_postgres` running?
|
||||||
2. Check `.env` - is DATABASE_URL correct (`patherly` not `decision_tree`)?
|
2. Check `.env` - is DATABASE_URL correct (`patherly` not `decision_tree`)?
|
||||||
3. Check venv: is `(venv)` prefix showing?
|
3. Check venv: is `(venv)` prefix showing?
|
||||||
|
|
||||||
### Frontend compile errors
|
### Frontend compile errors
|
||||||
|
|
||||||
1. Check `frontend/src/lib/utils.ts` exists (provides `cn()` function)
|
1. Check `frontend/src/lib/utils.ts` exists (provides `cn()` function)
|
||||||
2. Run `npm install` to ensure dependencies are installed
|
2. Run `npm install` to ensure dependencies are installed
|
||||||
|
|
||||||
### Tests failing
|
### Tests failing
|
||||||
|
|
||||||
1. Create test database: `docker exec -it patherly_postgres psql -U postgres -c "CREATE DATABASE patherly_test;"`
|
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`
|
2. Install dev deps: `pip install -r requirements-dev.txt`
|
||||||
3. Ensure pytest-asyncio version: `pip install pytest-asyncio==0.24.0`
|
3. Ensure pytest-asyncio version: `pip install pytest-asyncio==0.24.0`
|
||||||
|
|
||||||
### API 500 errors
|
### API 500 errors
|
||||||
|
|
||||||
1. Check server logs for datetime errors (timezone issue)
|
1. Check server logs for datetime errors (timezone issue)
|
||||||
2. Ensure all datetimes use `datetime.now(timezone.utc)`
|
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
|
## Quick Reference
|
||||||
|
|
||||||
| What | Where |
|
| What | Where |
|
||||||
@@ -619,12 +685,14 @@ const response = await api.get('/api/v1/trees')
|
|||||||
## Railway Deployment
|
## Railway Deployment
|
||||||
|
|
||||||
### Production
|
### Production
|
||||||
|
|
||||||
- **Frontend:** https://app.patherly.com
|
- **Frontend:** https://app.patherly.com
|
||||||
- **Backend:** https://api.patherly.com
|
- **Backend:** https://api.patherly.com
|
||||||
- **Database:** Railway-managed PostgreSQL
|
- **Database:** Railway-managed PostgreSQL
|
||||||
- Deploys automatically on push to `main`
|
- Deploys automatically on push to `main`
|
||||||
|
|
||||||
### PR Environments
|
### PR Environments
|
||||||
|
|
||||||
Railway creates isolated preview environments for each pull request.
|
Railway creates isolated preview environments for each pull request.
|
||||||
|
|
||||||
**Workflow:**
|
**Workflow:**
|
||||||
@@ -656,6 +724,54 @@ Railway creates isolated preview environments for each pull request.
|
|||||||
**Debug Endpoints (available in PR environments):**
|
**Debug Endpoints (available in PR environments):**
|
||||||
- `/debug/cors` - Check CORS configuration (allow_railway_origins, cors_mode)
|
- `/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
|
## Contact
|
||||||
|
|||||||
Reference in New Issue
Block a user