Migrations must use sequential numbered prefixes (e.g., 040_desc.py) with --rev-id flag. Never use auto-generated revision IDs. Updated both the lessons learned section and the development commands. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
414 lines
24 KiB
Markdown
414 lines
24 KiB
Markdown
# CLAUDE.md - Patherly / ResolutionFlow Project Context
|
|
|
|
> **Last Updated:** February 17, 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 content (CSS Grid). See [UI-DESIGN-SYSTEM.md](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](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_type` column values unchanged in DB.
|
|
- **Rebrand guide:** [REBRAND-IMPLEMENTATION-GUIDE.md](REBRAND-IMPLEMENTATION-GUIDE.md)
|
|
|
|
**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). Use "Flows" not "Trees" in all user-facing text; use "Projects" not "Procedures" for procedural flows. Reference [UI-DESIGN-SYSTEM.md](UI-DESIGN-SYSTEM.md) for layout patterns, navigation, 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
|
|
|
|
- Maintenance flows: `maintenance` tree_type, batch session launch, saved target lists, APScheduler cron scheduling, maintenance detail page
|
|
- 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
|
|
- **Scheduling:** APScheduler 3.x (async, in-process with FastAPI lifespan) + croniter + pytz
|
|
|
|
### 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 # (Deprecated — consolidated into CLAUDE.md)
|
|
└── 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/)
|
|
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
|
|
|
|
### 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<string, unknown>` 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.
|
|
|
|
**16. tree_type has three values:** `'troubleshooting' | 'procedural' | 'maintenance'`. Maintenance reuses the procedural execution engine. Use `PROCEDURAL_TREE_TYPES` set from `core/tree_validation.py` when checking for step-based flow types.
|
|
|
|
**17. Alembic autogenerate can be destructive:** `alembic revision --autogenerate` may generate DROP TABLE/ALTER COLUMN ops for unrelated tables (especially junction tables and tables with complex FKs). Always review generated migrations carefully. Prefer manual migrations for new tables: `alembic revision -m "desc"` then write the `upgrade()`/`downgrade()` by hand.
|
|
|
|
**18. Pydantic partial updates — use `model_fields_set`:** When a PUT/PATCH endpoint needs to distinguish "field not sent" from "field sent as null", check `data.model_fields_set` instead of `data.field is not None`. This allows clients to explicitly clear nullable fields like `description`.
|
|
|
|
**19. `gh pr merge` fails with worktrees:** When `main` is checked out in the primary worktree, `gh pr merge` crashes with "fatal: 'main' is already used by worktree". Use the API directly instead: `gh api repos/ORG/REPO/pulls/N/merge --method PUT --field merge_method=squash`
|
|
|
|
**20. `'answer'` node type in TreeStructure:** `answer` is a transient stub type used only in the canvas editor. Any code that switches on `node.type` (validation, markdown serializer, session nav guard) must explicitly handle `'answer'` or it will hit an unhandled-type error.
|
|
|
|
**21. Test fixtures in `conftest.py`:** Available fixtures are `client` (async HTTP client), `test_db` (async session), `test_user` (registers user, returns email/password/user_data), `auth_headers` (Bearer token dict), `test_tree` (creates a tree), `test_admin` (super_admin user), `admin_auth_headers` (admin Bearer token). There is NO `async_client` or `engineer_token` fixture.
|
|
|
|
**22. Worktree venv path:** Git worktrees (`.worktrees/*/`) do NOT have their own Python venv. Use the main repo's venv: `backend/venv/bin/python -m pytest ...` from the worktree directory.
|
|
|
|
**23. Action nodes navigate via `next_node_id`, not `children`:** `TreeNavigationPage.tsx` handles action nodes by following `next_node_id` only — the `children` array on action nodes is ignored at runtime. Action nodes without `next_node_id` render no "Continue" button (dead end). Any AI generation or manual tree editing must set `next_node_id` on action nodes.
|
|
|
|
**24. Anthropic model IDs require full dated version string:** `claude-haiku-4-5` is invalid; must be `claude-haiku-4-5-20251001`. See `backend/app/core/config.py` → `AI_MODEL`.
|
|
|
|
**25. Claude API may wrap JSON responses in markdown fences:** When parsing AI-generated JSON, always strip ` ```json ... ``` ` fences before parsing. See `_strip_markdown_fences()` in `ai_tree_generator_service.py`.
|
|
|
|
**26. `sessionsApi.list` supports `batch_id` filter (added Feb 2026):** Both backend `GET /sessions` and frontend `SessionListParams` accept `batch_id` for querying all sessions in a maintenance batch. Use `sessionsApi.list({ batch_id })` to fetch batch-scoped sessions.
|
|
|
|
**27. Maintenance batch sessions are created all-at-once at launch:** All sessions in a batch exist immediately after `batchLaunchApi.launch()` with `batch_id` + `target_label` set. `started_at` is null until a user begins executing that target — there is no "pending session creation" state.
|
|
|
|
**28. AI tests in CI need `ai_enabled` mock:** Backend tests that hit AI endpoints must mock `settings.ai_enabled = True` via `PropertyMock` since CI has no `ANTHROPIC_API_KEY`. See `tests/test_ai_chat.py` `_enable_ai` fixture pattern.
|
|
|
|
**29. ESLint `no-unused-vars` has no `argsIgnorePattern`:** Underscore-prefixed callback params (e.g., `_count`) still trigger errors. Use `// eslint-disable-next-line @typescript-eslint/no-unused-vars` or remove the param if the type signature allows it.
|
|
|
|
**30. Alembic `env.py` must import all models:** New models won't be discovered by `--autogenerate` unless imported in `alembic/env.py`. If a migration runs but the table isn't created, check imports first.
|
|
|
|
**31. JSONB fields — convert datetime to `.isoformat()` string:** Storing `datetime` objects directly in JSONB columns causes serialization errors. Always convert: `"timestamp": datetime.now(timezone.utc).isoformat()`.
|
|
|
|
**32. Export pipeline order matters:** Generate export → resolve session variables → apply redaction. Redaction MUST run last or sensitive data injected via variables bypasses it. See `sessions.py` export endpoint.
|
|
|
|
**33. Railway: `DATABASE_URL_SYNC` is a property, not an env var:** It derives from `DATABASE_URL` by replacing `postgresql+asyncpg://` with `postgresql://`. Delete any stale `DATABASE_URL_SYNC` variable in Railway dashboard.
|
|
|
|
**34. Railway: run migrations in Docker CMD, not `releaseCommand`:** `releaseCommand` in `railway.toml` is unreliable. Use `CMD alembic upgrade head && uvicorn ...` in the Dockerfile instead.
|
|
|
|
**35. `bcrypt==4.0.1` pinned for passlib compatibility:** Newer bcrypt versions break password hashing. Keep `bcrypt==4.0.1` and `passlib[bcrypt]==1.7.4` pinned in `requirements.txt`.
|
|
|
|
**36. Email validator rejects `.local` TLD:** Pydantic's email validation (via `email-validator`) rejects `.local` as a reserved TLD. Use `example.com` for test/seed user emails.
|
|
|
|
**37. First deployed user needs manual admin promotion:** New users default to `engineer` role. Promote via SQL: `UPDATE users SET role = 'admin' WHERE email = '...';` then re-login for new JWT.
|
|
|
|
**38. Alembic migrations MUST use sequential numbered prefixes:** Check `backend/alembic/versions/` for the highest numbered migration and use the next number. Format: `XXX_descriptive_name.py` (e.g., `040_add_whatever.py`). NEVER use auto-generated revision IDs like `0f1ca2af3647`. Always pass `--rev-id` flag: `alembic revision --autogenerate -m "desc" --rev-id=040`.
|
|
|
|
---
|
|
|
|
## 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`
|
|
|
|
---
|
|
|
|
## Design System (Purple Gradient Accent)
|
|
|
|
- **Theme:** Dark-only, purple gradient accents — NO monochrome `text-white/N` or `glass-card` patterns
|
|
- **Backgrounds:** `bg-background` (page), `bg-card` (cards/inputs/modals)
|
|
- **Cards:** `bg-card border border-border rounded-xl`
|
|
- **Buttons:** Primary: `bg-gradient-brand text-white shadow-lg shadow-primary/20 hover:opacity-90`. Secondary: `border border-border text-muted-foreground hover:bg-accent hover:text-foreground`
|
|
- **Inputs:** `border-border bg-card text-foreground placeholder:text-muted-foreground` + focus: `focus:border-primary focus:ring-1 focus:ring-primary/20`
|
|
- **Text:** `text-foreground` → `text-muted-foreground` (two levels only)
|
|
- **Borders:** `border-border` (single token, not opacity variants)
|
|
- **Hover states:** `hover:bg-accent` (backgrounds), `hover:text-foreground` (text)
|
|
- **Active/selected:** `bg-accent text-foreground` or `border-primary/30 bg-primary/10`
|
|
- **Functional color only:** emerald-400 (success), red-400 (error), yellow-400 (warning), blue-400 (info)
|
|
- **CSS variables:** Defined in `index.css` `:root` — `--primary`, `--card`, `--border`, `--accent`, `--muted-foreground`, etc.
|
|
|
|
---
|
|
|
|
## 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.
|
|
- **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.
|
|
- **Account section layout:** `AccountLayout` has NO sidebar nav. Account sub-pages (categories, target-lists) are reached via link cards on `AccountSettingsPage.tsx`. New account pages: add route in `router.tsx` under `account` children + add a link card in `AccountSettingsPage`.
|
|
|
|
---
|
|
|
|
## 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 <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
|
|
|
|
### After Completing Work
|
|
When a feature, fix, or significant piece of work is finished and merged/committed:
|
|
1. **Update `CURRENT-STATE.md`** — move completed items, update "In Progress" and "What's Next" sections
|
|
2. **Update `03-DEVELOPMENT-ROADMAP.md`** — check off completed work, update phase status
|
|
3. **Close related GitHub Issues** — use `gh issue close #N` for any issues resolved by the work
|
|
4. **Update `CLAUDE.md`** if 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_URL` set with `https://` prefix on frontend service
|
|
- `ALLOW_RAILWAY_ORIGINS=true` enables 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>`
|
|
|
|
---
|
|
|
|
## 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) |
|
|
| Development Roadmap | [03-DEVELOPMENT-ROADMAP.md](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](04-FEATURE-SPECIFICATIONS.md) |
|
|
| Design System | [docs/plans/Frontend/DESIGN_SYSTEM_GUIDE.md](docs/plans/Frontend/DESIGN_SYSTEM_GUIDE.md) |
|