- Migration 030: add email, assigned_plan, trial_duration_days, email_sent_at
to invite_codes with CHECK constraints
- Resend email integration (graceful degradation when API key not set)
- Invite codes now support plan assignment (free/pro/team) and trial duration (1-90 days)
- Registration applies invite code plan/trial to new subscription
- Auto-downgrade expired trials on authenticated access
- Enriched GET /admin/users/{id} with account, subscription, sessions, audit logs
- New endpoints: PUT /admin/users/{id}/subscription/plan and extend-trial
- Frontend: enhanced invite codes page with email, plan, trial fields
- Frontend: new user detail page at /admin/users/:userId
- Fixed API path drift: /invite-codes -> /invites
- 11 new backend tests, 416 total passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
305 lines
11 KiB
Markdown
305 lines
11 KiB
Markdown
# CLAUDE.md - Patherly / ResolutionFlow Project Context
|
|
|
|
> **Last Updated:** February 11, 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:** Monochrome dark-only — black backgrounds, white text with opacity, Inter font
|
|
- **CSS utilities:** `glass-card`, `glass-card-hover`, `glass-card-glow`, `glass-stat` (in `index.css`)
|
|
- **Logo:** Inline SVG in `BrandLogo.tsx`
|
|
- **Design system guide:** `docs/plans/Frontend/DESIGN_SYSTEM_GUIDE.md`
|
|
|
|
When adding new pages/components: use "ResolutionFlow" branding, monochrome design, `glass-card` containers, `text-white` hierarchy, white primary buttons, functional color only for status.
|
|
|
|
---
|
|
|
|
## 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, 29+ migrations
|
|
- **Detailed status:** [CURRENT-STATE.md](CURRENT-STATE.md)
|
|
|
|
### What's In Progress
|
|
|
|
- Custom step continuation flow refinements (Phase 2.5)
|
|
- Tree forking from sessions with custom steps
|
|
|
|
---
|
|
|
|
## 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 — monochrome glass-morphism (dark-only)
|
|
- **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, library, step-library, ui
|
|
│ │ ├── hooks/ # usePermissions, useSessionTimer, useKeyboardShortcuts
|
|
│ │ ├── pages/ # All page components
|
|
│ │ ├── store/ # Zustand stores (auth, treeEditor, 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=<openssl rand -hex 32>
|
|
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
|
|
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`).
|
|
|
|
**8. CORS errors can mask 500s:** Check backend logs first. Also run `alembic upgrade head` after pulling changes.
|
|
|
|
**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`)
|
|
```
|
|
|
|
---
|
|
|
|
## 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` (any active), `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 `<span>` 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.
|
|
|
|
---
|
|
|
|
## 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`
|
|
- **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 <noreply@anthropic.com>`
|
|
- 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|<email>`
|
|
|
|
---
|
|
|
|
## 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) |
|