Add standalone P&ID designer app#2
Conversation
Extracts P&ID designer from EngineDesign into its own top-level app at pid-designer/. Includes: - FastAPI backend on port 8001 with git-backed diagram persistence (load, autosave, checkpoint, history, version restore) - React/Vite frontend on port 5174 with pan/select modes, undo/redo, branching edges, fluid type coloring, and draggable labels - dev.sh to start both services with one command Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
|
||
| const onMouseMove = useCallback((e: React.MouseEvent<SVGGElement>) => { | ||
| const svg = (e.currentTarget as SVGElement).closest('svg'); | ||
| if (!svg || !pathRef.current) return; |
There was a problem hiding this comment.
Branching edge mouse guard
High Severity
onMouseMove returns immediately because it requires pathRef.current, but no path element ever receives that ref. The branch preview dot never appears and clicks cannot split edges, so advertised branching on pipes does not work.
Reviewed by Cursor Bugbot for commit 609b0a5. Configure here.
| }).catch(() => {}); | ||
| }, 1000); | ||
| return () => clearTimeout(t); | ||
| }, [nodes, edges]); |
There was a problem hiding this comment.
Autosave overwrites before load
High Severity
The canvas starts empty and schedules autosave one second after every nodes/edges change, without waiting for /api/pid/load. If load is slow, fails, or the backend errors, autosave can POST an empty diagram and overwrite pid_main.json on disk.
Reviewed by Cursor Bugbot for commit 609b0a5. Configure here.
| } | ||
|
|
||
| let _idCounter = 1; | ||
| const genId = () => `node_${_idCounter++}`; |
There was a problem hiding this comment.
Node id counter resets
High Severity
New nodes use genId() from a module-level counter that always starts at 1 on page load. After loading a saved diagram that already contains node_1, node_3, etc., the next dropped component can reuse an existing id and break React Flow state.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 609b0a5. Configure here.
- Use plain NodeProps (no generic) in all node components — @xyflow/react v12 changed the NodeProps generic signature - Remove sourceHandle/targetHandle from BranchableEdge destructure — not on EdgeProps in v12 - Fix unused 'i' variable in PIDToolbar history map - Remove missing @types/node from tsconfig.node.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| continue | ||
| parts = line.split("|", 2) | ||
| if len(parts) == 3: | ||
| entries.append({"hash": parts[0], "title": parts[1], "timestamp": parts[2]}) |
There was a problem hiding this comment.
History breaks on pipe titles
Medium Severity
History lines join hash, subject, and ISO time with |, then split with split("|", 2). Checkpoint titles containing | produce wrong titles and timestamps in the History UI and confuse restore labels.
Reviewed by Cursor Bugbot for commit cd9402f. Configure here.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This reverts commit 8dd4212.
| index.current = history.current.length - 1; | ||
| }, 300); | ||
| return () => { if (timer.current) clearTimeout(timer.current); }; | ||
| }, [nodes, edges]); |
There was a problem hiding this comment.
Undo restores empty canvas
Medium Severity
Undo history is seeded with an empty snapshot and is not reset after a successful load, so one undo after opening the designer can clear the entire diagram.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d0e413f. Configure here.
| }; | ||
| window.addEventListener('keydown', handler); | ||
| return () => window.removeEventListener('keydown', handler); | ||
| }, [setNodes]); |
There was a problem hiding this comment.
Shortcuts fire while typing
Medium Severity
Global keydown handlers for rotate (R), pan (V), and box select (B) do not ignore events when focus is in an input or textarea, so typing in labels or checkpoint fields triggers canvas actions.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d0e413f. Configure here.
|
|
||
| GIT_ROOT = _git_root() | ||
| # Path used in `git show <hash>:<path>` — must be relative to the git repo root. | ||
| GIT_DIAGRAM_PATH = str(DIAGRAM_PATH.relative_to(GIT_ROOT)) |
There was a problem hiding this comment.
Git root resolved at import
Medium Severity
_git_root() ignores git exit status and module-level GIT_DIAGRAM_PATH is computed at import; a failed rev-parse can make router import crash or break version restore paths.
Reviewed by Cursor Bugbot for commit d0e413f. Configure here.
| @router.get("/load") | ||
| async def load_diagram(): | ||
| """Load the current diagram from disk.""" | ||
| return _read_diagram() |
There was a problem hiding this comment.
Load crashes on bad JSON
Medium Severity
_read_diagram calls json.loads without handling decode errors, so a corrupted pid_main.json causes /api/pid/load to return an unhandled 500 instead of a safe fallback.
Reviewed by Cursor Bugbot for commit d0e413f. Configure here.
Runs on changes to pid-designer/** — two jobs: TypeScript build (npm run build) and backend import check (pip install + python3 -c "import backend.main"). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
There are 10 total unresolved issues (including 8 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 64b27b5. Configure here.
| }).catch(() => {}); | ||
| }, 1000); | ||
| return () => clearTimeout(t); | ||
| }, [nodes, edges]); |
There was a problem hiding this comment.
Autosave can wipe diagram
High Severity
Autosave runs on the initial empty canvas and again after undo to the seeded empty snapshot, persisting { nodes: [], edges: [] } over pid_main.json if load is slow or the user undoes once.
Reviewed by Cursor Bugbot for commit 64b27b5. Configure here.
| _run_git("commit", "-m", commit_message) | ||
| _run_git("push") | ||
| except RuntimeError as e: | ||
| raise HTTPException(status_code=500, detail=f"git operation failed: {e}") |
There was a problem hiding this comment.
Checkpoint fails unchanged file
Medium Severity
After autosave has already written the same JSON, git commit often has nothing to commit and the checkpoint endpoint returns 500 even though the diagram on disk is current.
Reviewed by Cursor Bugbot for commit 64b27b5. Configure here.
requirements.txt was reverted; install fastapi/uvicorn/pydantic inline. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>


Extracts P&ID designer from EngineDesign into its own top-level app at pid-designer/. Includes:
Note
Medium Risk
Large new surface area; checkpoint/pull endpoints invoke real
git commit/push/pullon the host repo, which can surprise users or fail without credentials even though scope is isolated underpid-designer/.Overview
Adds a new top-level
pid-designer/app extracted from EngineDesign: a React + Vite + XYFlow editor and a FastAPI service on port 8001, withdev.shto run both and a path-scoped GitHub Actions workflow (frontendtsc/build, backend import check).The backend persists diagrams to
diagrams/pid_main.jsonand exposes/api/pid/*for load, debounced autosave, git pull, checkpoint (add/commit/push), commit history, and version restore viagit show.The UI adds a component palette, pan/select, undo/redo, rotation, branchable edges (click-to-junction), edge fluid-type coloring, draggable/editable labels, JSON import/export, and toolbar flows for checkpoint, history, and get-latest.
Vite proxies
/apito 8001; the frontend dev server uses port 5174.Reviewed by Cursor Bugbot for commit bb732d8. Bugbot is set up for automated code reviews on this repo. Configure here.