Skip to content

Conversation

@Vamsi-o
Copy link
Contributor

@Vamsi-o Vamsi-o commented Jan 14, 2026

  • Refactored user routes to improve middleware usage and logging.
  • Updated TypeScript configurations for better module resolution.
  • Introduced new UI components for workflow management, including a modal for creating workflows and a placeholder node for actions.
  • Enhanced existing components with improved styling and functionality.
  • Added new node configurations for Gmail and Google Sheets actions.
  • Improved error handling and logging in workflow execution.
  • Updated API integration for creating and managing workflows and nodes.

Summary by CodeRabbit

  • New Features

    • Added workflow creation interface with name and description input
    • Introduced interactive workflow canvas with visual node editor
    • Added support for multiple trigger and action types (Webhooks, Gmail, Google Sheets)
    • Implemented node configuration modal for customizing workflow parameters
    • Added placeholder nodes for extensible workflow building
  • Bug Fixes

    • Improved error handling and messaging across API endpoints

✏️ Tip: You can customize this high-level summary in your review settings.

- Refactored user routes to improve middleware usage and logging.
- Updated TypeScript configurations for better module resolution.
- Introduced new UI components for workflow management, including a modal for creating workflows and a placeholder node for actions.
- Enhanced existing components with improved styling and functionality.
- Added new node configurations for Gmail and Google Sheets actions.
- Improved error handling and logging in workflow execution.
- Updated API integration for creating and managing workflows and nodes.
Copilot AI review requested due to automatic review settings January 14, 2026 06:08
@coderabbitai
Copy link

coderabbitai bot commented Jan 14, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a comprehensive workflow canvas interface with node-based configuration system. Changes include a new React Flow-based workflow editor, backend route type adjustments, database schema updates for node positioning, node configuration registry, API client wrapper, and worker executor enhancements for error handling and credential context.

Changes

Cohort / File(s) Summary
Backend Route Updates
apps/http-backend/src/routes/userRoutes/userMiddleware.ts, apps/http-backend/src/routes/userRoutes/userRoutes.ts
Commented out debug logging; removed or relaxed userMiddleware on certain routes (e.g., createAvailableTriggers); updated request handler signatures from AuthRequest to generic Request; consolidated error messages; adjusted response payload shapes (Data vs data keys) across credential, workflow, trigger, and node endpoints.
Frontend Workflow Canvas
apps/web/app/workflows/[id]/page.tsx
New client-side React Flow–based workflow canvas component with state management for nodes, edges, and UI modals; handlers for trigger/action selection with database API integration; node configuration modal integration.
Node Components & Types
apps/web/app/components/NODES/BaseNode.tsx, apps/web/app/components/nodes/TriggerNode.tsx, apps/web/app/workflows/[id]/components/nodes/PlaceholderNode.tsx, apps/web/app/workflows/[id]/components/ConfigModal.tsx
New BaseNode component for rendering action/trigger nodes with handles and optional action buttons; TriggerNode made icon and config optional; new PlaceholderNode for action placeholders; new ConfigModal for per-node configuration with dynamic form rendering.
Node Configuration System
apps/web/app/lib/nodeConfigs/index.ts, apps/web/app/lib/nodeConfigs/webhook.trigger.ts, apps/web/app/lib/nodeConfigs/gmail.action.ts, apps/web/app/lib/nodeConfigs/googleSheet.action.ts, apps/web/app/lib/types/node.types.ts
New NodeConfig and ConfigField type definitions; registry-based lookup system for node configurations by label or id; webhook trigger, Gmail action, and Google Sheets action configuration definitions.
Frontend API & UI
apps/web/app/lib/api.ts, apps/web/app/components/ui/Design/WorkflowButton.tsx, apps/web/app/components/ui/Design/WorkflowCard.tsx, apps/web/app/page.tsx
New centralized axios-based API client with endpoints for workflows, triggers, nodes, and credentials; new WorkflowButton and WorkflowCard components for workflow creation; integration of WorkflowButton into authenticated homepage.
Type & Schema Updates
apps/web/app/types/workflow.types.ts, packages/common/src/index.ts
Fixed typo in NodeType.data (TYpe → Type); made config property optional in NodeType; made Config and TriggerType optional in TriggerSchema; renamed Node.position to Node.stage and made optional; added optional description to WorkflowSchema; introduced HOOKS_URL constant.
Database Schema Changes
packages/db/prisma/schema.prisma, packages/db/src/seed.ts
Changed Node.position type from Int to Json; added Node.stage field; made Node.AvailableNode relation optional; updated NodeExecution timestamps to UTC-based generated defaults; adjusted seed payload from numeric position to stage + coordinate object.
UI Components & Build
packages/ui/src/components/button.tsx, packages/ui/src/components/card.tsx
Added semicolons to button component imports and declarations (formatting only); introduced new Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter sub-components with base styling and data-slot attributes.
Worker & Build Metadata
apps/worker/src/engine/executor.ts, apps/http-backend/tsconfig.tsbuildinfo, packages/db/tsconfig.tsbuildinfo
Activated previously commented error handling path (sets workflow status to "Failed" on execution failure); added userId and credId to node execution context; normalized TypeScript build metadata.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Canvas as Workflow Canvas
    participant API as Backend API
    participant DB as Database
    
    User->>Canvas: Click "Add Trigger"
    Canvas->>API: GET /user/getAvailableTriggers
    API->>DB: Query available triggers
    DB-->>API: Return trigger list
    API-->>Canvas: Return trigger options
    Canvas->>User: Show trigger selector
    
    User->>Canvas: Select trigger
    Canvas->>API: POST /user/create/trigger
    API->>DB: Create trigger node
    DB-->>API: Return created trigger
    API-->>Canvas: Trigger created
    Canvas->>Canvas: Add trigger node + action placeholder
    
    User->>Canvas: Click "Add Action" on placeholder
    Canvas->>API: GET /user/getAvailableNodes
    API->>DB: Query available nodes
    DB-->>API: Return node list
    API-->>Canvas: Return node options
    Canvas->>User: Show action selector
    
    User->>Canvas: Select action
    Canvas->>API: POST /user/create/node
    API->>DB: Create action node
    DB-->>API: Return created node
    API-->>Canvas: Node created
    Canvas->>Canvas: Add action node + new placeholder, rewire edges
    
    User->>Canvas: Configure action node
    Canvas->>Canvas: Open ConfigModal
    User->>Canvas: Submit configuration
    Canvas->>API: PUT /user/update/node
    API->>DB: Update node config
    DB-->>API: Update confirmed
    API-->>Canvas: Config saved
    Canvas->>Canvas: Close modal, update node display
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 A canvas born from nodes and flow,
Where triggers spark and actions grow,
With configs set and edges drawn,
The workflow craft continues on! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: refactoring user routes and adding/enhancing workflow UI components are the primary focuses across the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
apps/http-backend/src/routes/userRoutes/userRoutes.ts (2)

76-109: Security concern: Authentication disabled on trigger creation endpoint.

The userMiddleware has been commented out, allowing unauthenticated users to create available triggers. If this is intentional (e.g., for admin seeding), consider:

  1. Protecting this with an admin-specific middleware or API key
  2. Adding a comment explaining why authentication is bypassed
  3. Moving this to an admin-only route
🔒 Suggested fix to re-enable authentication
 router.post(
   "/createAvaliableTriggers",
-  // userMiddleware,
+  userMiddleware,
-  async (req: Request, res: Response) => {
+  async (req: AuthRequest, res: Response) => {

354-356: Typo in response key: meesage should be message.

This typo could break client-side error handling that expects a message key.

✏️ Fix typo
       return res.status(statusCodes.INTERNAL_SERVER_ERROR).json({
-        meesage: "Internal Server Error From  getting workflows for the user",
+        message: "Internal Server Error From getting workflows for the user",
       });
apps/web/app/types/workflow.types.ts (2)

23-28: Rename AvailabeAction to AvailableAction (missing 'l' in "Available").

The interface is imported and used in apps/web/app/hooks/useActions.ts at least once, so the rename will need to be coordinated across both files.


12-16: Fix typos in interface names: EdageEdge and AvailabeActionAvailableAction.

Both interfaces contain typos:

  • Edage (line 12) appears unused and can be safely renamed.
  • AvailabeAction (line 23) is imported and used in apps/web/app/hooks/useActions.ts and must be updated there as well.
🤖 Fix all issues with AI agents
In `@apps/http-backend/src/routes/userRoutes/userRoutes.ts`:
- Around line 437-439: The PUT route handler declared as
router.put("/workflow/update", userMiddleware, (req: AuthRequest, res: Response)
=> { }) is empty and will hang requests; either implement the handler or remove
it. To fix, add a concrete implementation inside that arrow function: validate
req.body, call the appropriate service/utility (e.g., updateUserWorkflow or
whatever existing workflow update function is used elsewhere), handle errors
with try/catch and return an appropriate response status (200 with updated data
or 204 on success, and 4xx/5xx on errors), or if the feature isn't ready return
a clear short response such as res.status(501). Ensure the handler uses the
AuthRequest user info provided by userMiddleware and always sends a response in
all code paths.

In `@apps/http-backend/tsconfig.tsbuildinfo`:
- Line 1: Remove all tracked TypeScript incremental build artifacts and add a
comprehensive ignore rule: run git rm --cached on every tracked tsbuildinfo file
(e.g., apps/hooks/tsconfig.tsbuildinfo, apps/processor/tsconfig.tsbuildinfo,
apps/worker/tsconfig.tsbuildinfo, packages/nodes/tsconfig.tsbuildinfo and the
root apps/http-backend/tsconfig.tsbuildinfo) and update the root .gitignore to
include a complete pattern like **/*.tsbuildinfo (or explicit entries for each
package/app) so these autogenerated files are no longer committed.

In `@apps/web/app/lib/nodeConfigs/googleSheet.action.ts`:
- Around line 36-48: The form field name is incorrectly set to "action" in the
dropdown config (object with name: "action"); it must match the rest of the code
which expects "operation". Change the field key from "action" to "operation" in
the dropdown definition (and keep the same options/defaultValue/description) so
submitted data aligns with SaveConfigFormData and updateConfigData; verify any
references to this field in the same module use "operation" as well.

In `@apps/web/app/workflows/`[id]/components/ConfigModal.tsx:
- Around line 127-145: The form inputs in ConfigModal.tsx are uncontrolled so
user edits are lost; initialize a local state object (e.g., formValues) keyed by
nodeConfig.fields' name (use useState, populated from nodeConfig or default
placeholders) and update it in an onChange handler attached to the rendered
<input> for each field; set each input's value to formValues[field.name];
finally update the call in handleSave to include the collected formValues (merge
with existing HOOKS_URL behavior) so all dynamic field values are passed back
when saving.
- Around line 23-24: The code is using userAction.setUserId (an action creator)
as if it were the userId; replace this with a Redux selector: import and use
useSelector (from react-redux) to read the userId from state (e.g., call
useSelector(state => state.user.id) or the existing selector function like
selectUserId) inside the ConfigModal component, remove the incorrect cast of
userAction.setUserId, and update any console/log references to use the
selector-derived userId instead of the action creator reference.

In `@apps/web/app/workflows/`[id]/page.tsx:
- Around line 59-88: handleNodesChange currently fires api.triggers.update and
api.nodes.update without awaiting or handling errors, causing unhandled
rejections and possible UI/backend divergence; modify handleNodesChange to await
(or at least attach .catch) the update promises for api.triggers.update and
api.nodes.update, log/report errors via your logger or show a toast, and on
failure revert the UI change by calling onNodesChange with the previous node
state from nodes to keep UI/backend consistent; additionally wrap rapid position
updates with a debounce (e.g., per-node debounce) so you only send the final
position after dragging to reduce API churn.
- Around line 425-445: The onSave handler currently expects (nodeId, config) but
ConfigModal calls onSave(config, userId); update the handler signature to
onSave={async (config, userId) => { const nodeId = selectedNode?.id; if
(!nodeId) return; /* then use nodeId below */ if (nodes.find(n => n.id ===
nodeId)?.data.nodeType === "trigger") await api.triggers.update({ TriggerId:
nodeId, Config: config }); else await api.nodes.update({ NodeId: nodeId, Config:
config }); setNodes(prev => prev.map(node => node.id === nodeId ? { ...node,
data: { ...node.data, config, isConfigured: true } } : node)); }} so it matches
ConfigModal calls and uses selectedNode.id as the node identifier (or
validate/throw if missing).

In `@apps/worker/src/engine/executor.ts`:
- Around line 54-64: When handling the failed execute result, ensure the error
is serialized to a string before saving and add the failing node identifier to
both the DB update and logs: convert execute.error to a reliable string (e.g.,
use execute.error?.message || String(execute.error) or JSON.stringify with a
fallback) and pass that into prismaClient.workflowExecution.update for the error
field; also include the current node identifier from the executor scope (e.g.,
nodeId, currentNode.id or node.name — whatever symbol is used in this file) as a
new field (e.g., failedNodeId/failedNodeName) and emit a processLogger or logger
call that records the workflowExecutionId, the failing node identifier, and the
serialized error.

In `@packages/common/src/index.ts`:
- Around line 4-5: BACKEND_URL and HOOKS_URL are hardcoded to localhost which
breaks deployments; change them to read from environment variables with sensible
defaults. Update the constants BACKEND_URL and HOOKS_URL in
packages/common/src/index.ts to use process.env.BACKEND_URL and
process.env.HOOKS_URL (or use BACKEND_URL as the single source if both should
match), falling back to "http://localhost:3002" when the env vars are absent,
and ensure exports remain unchanged so callers keep working.
- Around line 28-34: NodeSchema was renamed to use stage but frontend still
sends Position, causing validation failures; change the outgoing payload keys so
they send stage instead of Position. Specifically, update the places that
currently set "Position: 1" and "Position: context.position" to use "stage: 1"
and "stage: context.position" respectively, and ensure any related types/objects
(payload builders or serialize functions) that reference Position are updated to
stage to match NodeSchema.

In `@packages/db/prisma/schema.prisma`:
- Around line 109-110: The completedAt field currently has a db-generated
default which sets a timestamp on creation; remove the
`@default`(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) from the completedAt
field (leave it as DateTime? `@db.Timestamptz`(6) and nullable) so it stays null
until explicitly updated, while keeping startedAt's default intact; after
changing the schema run the Prisma migration to update the DB schema and ensure
application code sets completedAt when the execution finishes.
- Around line 68-71: AvailableNodeID is non-nullable but the relation
AvailableNode is optional, causing a schema mismatch; decide intended
cardinality and make them consistent: if the relation must be required, change
AvailableNode? to AvailableNode (remove the question mark) so AvailableNodeID
stays String and the relation is required; otherwise, make the foreign key
nullable by changing AvailableNodeID to String? so the optional relation
AvailableNode? aligns with a nullable FK. Update the Prisma model accordingly
and regenerate the client.
🟡 Minor comments (15)
apps/worker/src/engine/executor.ts-52-52 (1)

52-52: Object interpolation in template string will print [object Object].

Using an object directly in a template string produces unhelpful output. Use JSON.stringify for readable logging:

-    console.log(`Executing with context: ${context}`);
+    console.log(`Executing with context: ${JSON.stringify(context)}`);
apps/worker/src/engine/executor.ts-37-37 (1)

37-37: Incorrect error check on Prisma update result.

update.error refers to the error field on the WorkflowExecution record, not a Prisma operation error. Prisma throws exceptions on failure rather than returning an error property. This check will always pass if the record has no error field value.

Either wrap the update in a try/catch block or simply log unconditionally:

-  if (!update.error) console.log("updated the workflow execution");
+  console.log("updated the workflow execution");

Alternatively, if you want to handle Prisma errors:

+  try {
     const update = await prismaClient.workflowExecution.update({
       where: {
         id: workflowExecutionId,
       },
       data: {
         status: "InProgress",
       },
     });
-  if (!update.error) console.log("updated the workflow execution");
+    console.log("updated the workflow execution");
+  } catch (err) {
+    console.error("Failed to update workflow execution status:", err);
+    return;
+  }
apps/http-backend/src/routes/userRoutes/userRoutes.ts-389-391 (1)

389-391: Same typo: meesage should be message.

✏️ Fix typo
       return res.status(statusCodes.INTERNAL_SERVER_ERROR).json({
-        meesage: "Internal Server Error From  getting workflows for the user",
+        message: "Internal Server Error From getting workflows for the user",
       });
apps/http-backend/src/routes/userRoutes/userRoutes.ts-617-621 (1)

617-621: Same issue: use 200 OK instead of 201 Created for updates.

🔧 Fix status code
       if (updatedTrigger)
-        return res.status(statusCodes.CREATED).json({
+        return res.status(statusCodes.OK).json({
           message: "Trigger updated",
           data: updatedTrigger,
         });
apps/http-backend/src/routes/userRoutes/userRoutes.ts-578-582 (1)

578-582: Incorrect HTTP status code for update operation.

PUT/update operations should return 200 OK, not 201 Created. HTTP 201 is semantically reserved for resource creation.

🔧 Fix status code
       if (updateNode)
-        return res.status(statusCodes.CREATED).json({
+        return res.status(statusCodes.OK).json({
           message: "Node updated",
           data: updateNode,
         });
apps/http-backend/src/routes/userRoutes/userRoutes.ts-259-274 (1)

259-274: Missing response for edge cases.

The findMany always returns an array (possibly empty), so the if (creds) check will always be truthy. However, if somehow the block doesn't execute or an unexpected path is taken, no response is sent. This could leave requests hanging.

🔧 Suggested fix to ensure response is always returned
       const creds = await prismaClient.credential.findMany({
         where: { userId: userId },
       });
-      if (creds) {
-        return res.status(statusCodes.OK).json({
-          message: "Fetched all credentials of the User!",
-          data: creds,
-        });
-      }
+      return res.status(statusCodes.OK).json({
+        message: "Fetched all credentials of the User!",
+        data: creds,
+      });
     } catch (e) {
apps/web/app/lib/nodeConfigs/googleSheet.action.ts-20-27 (1)

20-27: Fix field name casing: spreadsheetId in config should match spreadSheetId in GoogleSheetFormClientProps interface, or vice versa.

There is a confirmed inconsistency: the field is defined as spreadsheetId (lowercase) in this config file and throughout the backend services, but the GoogleSheetFormClient component interface expects spreadSheetId (capital S). This mismatch causes initialData not to populate correctly into the form (see GoogleSheetFormClient.tsx line 34 accessing initialData?.spreadSheetId). Either rename this field to spreadSheetId for consistency with the component props, or update the component interface to use spreadsheetId to match the backend and action config. The backend and service layer use lowercase consistently, so updating the component interface would be the preferred approach.

apps/web/app/components/ui/Design/WorkflowCard.tsx-21-21 (1)

21-21: Description field is captured but never sent to the API.

The description state (line 21) is collected from user input but not passed to api.workflows.create() (line 31). Either include it in the API call or remove the field if it's not needed.

💡 If description should be sent
-const create = await api.workflows.create(name, []);
+const create = await api.workflows.create(name, [], description);

This assumes the API accepts description as a third parameter. Verify the API signature.

Also applies to: 30-31

apps/web/app/components/ui/Design/WorkflowCard.tsx-33-33 (1)

33-33: Add defensive check for deeply nested response property.

Accessing create.data.Data.id will throw if the response structure is unexpected. Consider adding optional chaining or validation.

💡 Suggested defensive access
-const id = create.data.Data.id;
+const id = create.data?.Data?.id;
+if (!id) {
+  throw new Error("Invalid response: missing workflow ID");
+}
packages/common/src/index.ts-2-2 (1)

2-2: Remove unused import.

The number import from zod/v4 is not used anywhere in this file.

🧹 Proposed fix
 import z from "zod";
-import { number } from "zod/v4";
apps/web/app/components/ui/Design/WorkflowCard.tsx-51-55 (1)

51-55: Prevent overlay click from closing modal during loading.

Clicking the backdrop calls onClose even when loading is true, which could interrupt the submission.

💡 Proposed fix
     <div
       className="fixed inset-0 z-50 flex items-center justify-center bg-black/30 backdrop-blur-sm transition-all"
-      onClick={onClose}
+      onClick={loading ? undefined : onClose}
     >
apps/web/app/workflows/[id]/components/ConfigModal.tsx-30-35 (1)

30-35: Modal closes on error, preventing user from seeing failure and retrying.

The onClose() call in the finally block causes the modal to close even when save fails. Users lose context and must reopen the modal to retry. Consider only closing on success.

💡 Suggested fix
     } catch (error) {
       console.error("Save failed:", error);
+      // Optionally set error state to display to user
+      return; // Don't close on error
     } finally {
       setLoading(false);
-      onClose();
     }
+    onClose(); // Only close on success
   };
apps/web/app/workflows/[id]/page.tsx-49-49 (1)

49-49: Fix typo in error state initialization.

The initial state contains a stray single quote character which will cause the error state to always be non-empty.

-  const [error, setError] = useState<string>("'");
+  const [error, setError] = useState<string>("");
apps/web/app/lib/api.ts-35-40 (1)

35-40: triggers.update doesn't return the axios response.

Unlike other methods that implicitly return the axios promise, this method awaits without returning, meaning callers cannot access the response data.

   update: async (data: z.infer<typeof TriggerUpdateSchema>) => {
-    await axios.put(`${BACKEND_URL}/user/update/trigger`, data, {
+    return await axios.put(`${BACKEND_URL}/user/update/trigger`, data, {
       withCredentials: true,
       headers: { "Content-Type": "application/json" },
     });
   },
apps/web/app/components/NODES/BaseNode.tsx-102-106 (1)

102-106: Bug: "Configured" badge logic is incorrect.

The badge displays when data.onConfigure callback exists, but this callback is typically always present (for opening settings). It should likely check data.isConfigured or verify that config has meaningful values.

-        {data.onConfigure && (
+        {data.isConfigured && (
           <span className="ml-2 px-2 py-1 bg-green-100 text-green-800 text-xs rounded-full">
             ✓ Configured
           </span>
         )}

Note: This requires adding isConfigured?: boolean to the BaseNodeProps.data interface.

🧹 Nitpick comments (24)
packages/db/tsconfig.tsbuildinfo (1)

1-1: Consider excluding .tsbuildinfo files from version control.

TypeScript build information files are auto-generated compiler artifacts intended for incremental compilation. Committing them can lead to merge conflicts and build inconsistencies when team members use different TypeScript versions or have different build states.

Add *.tsbuildinfo to your .gitignore file and remove this file from the repository.

packages/db/src/seed.ts (1)

59-60: Minor formatting inconsistency.

The spacing around colons and commas is inconsistent with typical JavaScript/TypeScript conventions.

Suggested fix
-      stage: 1,
-      position : {x : 250 , y : 200},
+      stage: 1,
+      position: { x: 250, y: 200 },
apps/http-backend/src/routes/userRoutes/userRoutes.ts (3)

535-539: Redundant conditional check.

prismaClient.node.create() either returns the created node or throws an exception (caught by the catch block). The if (createdNode) check is unnecessary and removing it simplifies the code.

♻️ Simplify by removing redundant check
       });

-      if (createdNode)
-        return res.status(statusCodes.CREATED).json({
-          message: "Node created",
-          data: createdNode,
-        });
+      return res.status(statusCodes.CREATED).json({
+        message: "Node created",
+        data: createdNode,
+      });
     } catch (e) {

218-218: Consider logging a warning if BACKEND_URL is not configured.

The localhost:3002 fallback is fine for development, but in production, a missing BACKEND_URL could result in returning an incorrect auth URL to clients. Consider adding a startup check or warning log.


511-511: Remove or comment out debug logging.

Debug console.log statements should be removed or commented out before merging to avoid cluttering production logs.

🧹 Remove debug log
       const data = req.body;
-      console.log(" from http-backeden" , data);
+      // console.log("from http-backend", data);
apps/web/app/types/workflow.types.ts (1)

3-6: Consider using a more specific type for config.

Using any defeats TypeScript's type safety. Consider defining a proper type or using Record<string, unknown> for better type checking, similar to what's used in AvailableTrigger and AvailabeAction.

Suggested improvement
   data: {
     Type: "Trigger" | "Action";
     SelectedType: string;
-    label : string
-    config? : any
+    label: string;
+    config?: Record<string, unknown>;
   };
apps/web/app/components/nodes/TriggerNode.tsx (1)

12-20: Consider adding a fallback for when icon is undefined.

Since icon is now optional, rendering {data.icon} when undefined will display nothing, potentially leaving a visual gap in the UI. Consider providing a default icon or conditional rendering.

Suggested improvement
 export const TriggerNode = ({ data }: TriggerNodeProps) => {
   return (
     <div className="flex flex-col items-center p-4 bg-gray-800 rounded-lg border border-gray-600">
-      <div className="text-3xl">{data.icon}</div>
+      <div className="text-3xl">{data.icon ?? '⚡'}</div>
       <div className="text-white font-bold mt-2">{data.name}</div>
       <div className="text-gray-400 text-sm">{data.type}</div>
       <Handle type="source" position={Position.Right} />
     </div>
   );
 };
apps/web/app/workflows/[id]/components/nodes/PlaceholderNode.tsx (2)

14-26: Consider improving keyboard accessibility.

The clickable div element lacks keyboard accessibility. Users navigating with keyboards won't be able to interact with this element. Consider adding tabIndex, role, and keyboard event handlers, or use a <button> element.

Suggested improvement
     <div 
       onClick={data.onClick}
+      onKeyDown={(e) => e.key === 'Enter' && data.onClick?.()}
+      role="button"
+      tabIndex={0}
       className="border-2 border-dashed border-gray-300 rounded-lg bg-gray-50 hover:bg-gray-100 hover:border-blue-400 cursor-pointer transition-all min-w-[280px]"
     >

21-23: Consider using an icon component instead of emoji.

The emoji may render inconsistently across different platforms and browsers. Consider using a proper icon component (e.g., from a library like lucide-react or @heroicons/react) for consistent visual appearance.

packages/ui/src/components/card.tsx (1)

31-48: Consider using semantic HTML elements for better accessibility.

Using <div> for CardTitle and CardDescription misses the opportunity for semantic meaning. Consider using heading elements (<h3>, <h4>) for titles and <p> for descriptions, which improves accessibility and SEO.

Suggested improvement
-function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
+function CardTitle({ className, ...props }: React.ComponentProps<"h3">) {
   return (
-    <div
+    <h3
       data-slot="card-title"
       className={cn("leading-none font-semibold", className)}
       {...props}
     />
   )
 }

-function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
+function CardDescription({ className, ...props }: React.ComponentProps<"p">) {
   return (
-    <div
+    <p
       data-slot="card-description"
       className={cn("text-muted-foreground text-sm", className)}
       {...props}
     />
   )
 }
apps/web/app/page.tsx (1)

25-29: Consider using Tailwind margin classes instead of <br /> for spacing.

Using <br /> for layout spacing is a legacy HTML pattern. Prefer margin or padding utilities (e.g., mt-4) on the ParentComponent wrapper for better control and consistency with Tailwind-based styling.

Also, "ParentComponent" is a generic name—consider renaming to something more descriptive like WorkflowButton or CreateWorkflowButton in the import alias for clarity.

✨ Suggested improvement
-            <br />
-            <ParentComponent/>
+            <div className="mt-4">
+              <ParentComponent />
+            </div>
apps/web/app/components/ui/Design/WorkflowButton.tsx (1)

7-17: Rename ParentComponent to a more descriptive name.

The name ParentComponent is generic and doesn't convey purpose. Consider renaming to CreateWorkflowButton or WorkflowButtonWithModal to better reflect its functionality.

✨ Suggested rename
-export default function ParentComponent() {
+export default function CreateWorkflowButton() {
apps/web/app/lib/nodeConfigs/index.ts (1)

9-19: Consider adding collision detection for the registry.

The dual-mapping by label and id is flexible, but if two different configs share the same label or id, one will silently overwrite the other. At scale, consider adding a build-time or runtime check to detect collisions.

apps/web/app/lib/nodeConfigs/gmail.action.ts (1)

29-45: Inconsistent dependsOn usage across fields.

The to field has dependsOn: "credentialId", but subject and body don't. If the intent is to allow typing subject/body before selecting an account, this is fine. However, if all fields should be disabled until a credential is selected, add dependsOn: "credentialId" to all fields for consistency.

apps/web/app/workflows/[id]/components/ConfigModal.tsx (1)

136-141: Form only renders text inputs regardless of field type.

The ConfigField interface supports multiple types (dropdown, textarea, number, checkbox, password), but this code only renders <input type="text">. Consider rendering appropriate controls based on field.type.

apps/web/app/lib/nodeConfigs/webhook.trigger.ts (1)

1-33: Remove large block of commented-out code.

This 33-line commented block clutters the file. If the previous implementation is needed for reference, consider storing it in version control history or documentation instead.

♻️ Proposed fix
-// import { NodeConfig } from '../types/node.types';
-
-// export const webhookTriggerConfig: NodeConfig = {
-//   id: "webhook",
-//   type: "trigger",
-//   label: "Webhook",
-//   icon: "📡",
-//   description: "Trigger workflow on HTTP request",
-//   fields: [
-//     {
-//       name: "path",
-//       label: "Webhook Path",
-//       type: "text",
-//       required: true,
-//       placeholder: "/api/webhook/12345",
-//       description: "The HTTP path where this webhook will listen. Must be unique per workflow."
-//     },
-//     {
-//       name: "method",
-//       label: "HTTP Method",
-//       type: "dropdown",
-//       required: true,
-//       options: [
-//         { label: "POST", value: "POST" },
-//         { label: "GET", value: "GET" }
-//       ],
-//       defaultValue: "POST",
-//       description: "The HTTP method to accept (typically POST)."
-//     }
-//   ],
-//   summary: "Listen for HTTP requests on a unique webhook URL.",
-//   helpUrl: "https://docs.example.com/webhook-trigger"
-// };
-
 import { NodeConfig } from "../types/node.types";
packages/common/src/index.ts (1)

36-40: Consider stricter typing for position field.

Using z.any().optional() for position provides no validation. If position has a known structure (e.g., { x: number, y: number }), consider defining it explicitly:

const PositionSchema = z.object({
  x: z.number(),
  y: z.number(),
}).optional();

export const NodeUpdateSchema = z.object({
  NodeId: z.string(),
  Config: z.any().optional(),
  position: PositionSchema,
});
apps/web/app/workflows/[id]/page.tsx (3)

3-3: Remove unused import act.

The act import from React is not used anywhere in this component.

-import { useState, useEffect, act } from "react";
+import { useState } from "react";

Note: useEffect also appears unused in this file.


89-210: Remove large block of commented-out code.

This 120+ line commented block is dead code that should be removed. It clutters the file and makes maintenance harder. Version control preserves history if needed.


301-306: Remove unused variable currentActionNodes.

currentActionNodes is computed but never used, adding unnecessary overhead.

-      // Find all non-placeholder action nodes in the CURRENT state (after newNode is added)
-      const currentActionNodes = [
-        ...nodes.filter(
-          (n) => n.data.nodeType === "action" && !n.data.isPlaceholder
-        ),
-        newNode,
-      ];
-
       // Find all existing action nodes (NOT including newNode yet)
apps/web/app/components/NODES/BaseNode.tsx (2)

19-29: Consider using or removing unused props id and type.

The id and type props are destructured from the component parameters but are never used in the component body. If they're not needed, simplify the signature. If they might be needed for debugging or accessibility, consider adding them as data attributes.


108-116: Remove commented-out code block.

Dead code should be removed. Version control preserves history if restoration is needed.

apps/web/app/lib/api.ts (2)

59-70: Inconsistent naming: Credentials uses PascalCase.

For consistency with workflows, triggers, and nodes, consider renaming to credentials.

-  Credentials: {
+  credentials: {
     getCredentials: async (type: string) =>

7-71: Consider stronger typing and centralized axios configuration.

The API wrapper uses any for several payloads (Config, data in create methods). Consider:

  1. Defining proper TypeScript interfaces for request/response shapes
  2. Creating a shared axios instance with default config to reduce repetition of withCredentials and headers
♻️ Example: Centralized axios instance
const apiClient = axios.create({
  baseURL: BACKEND_URL,
  withCredentials: true,
  headers: { "Content-Type": "application/json" },
});

export const api = {
  workflows: {
    create: async (name: string, config: WorkflowConfig) =>
      apiClient.post("/user/create/workflow", { Name: name, Config: config }),
    // ...
  },
  // ...
};
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 96ba045 and f556da3.

📒 Files selected for processing (25)
  • apps/http-backend/src/routes/userRoutes/userMiddleware.ts
  • apps/http-backend/src/routes/userRoutes/userRoutes.ts
  • apps/http-backend/tsconfig.tsbuildinfo
  • apps/web/app/components/NODES/BaseNode.tsx
  • apps/web/app/components/nodes/TriggerNode.tsx
  • apps/web/app/components/ui/Design/WorkflowButton.tsx
  • apps/web/app/components/ui/Design/WorkflowCard.tsx
  • apps/web/app/lib/api.ts
  • apps/web/app/lib/nodeConfigs/gmail.action.ts
  • apps/web/app/lib/nodeConfigs/googleSheet.action.ts
  • apps/web/app/lib/nodeConfigs/index.ts
  • apps/web/app/lib/nodeConfigs/webhook.trigger.ts
  • apps/web/app/lib/types/node.types.ts
  • apps/web/app/page.tsx
  • apps/web/app/types/workflow.types.ts
  • apps/web/app/workflows/[id]/components/ConfigModal.tsx
  • apps/web/app/workflows/[id]/components/nodes/PlaceholderNode.tsx
  • apps/web/app/workflows/[id]/page.tsx
  • apps/worker/src/engine/executor.ts
  • packages/common/src/index.ts
  • packages/db/prisma/schema.prisma
  • packages/db/src/seed.ts
  • packages/db/tsconfig.tsbuildinfo
  • packages/ui/src/components/button.tsx
  • packages/ui/src/components/card.tsx
🧰 Additional context used
🧬 Code graph analysis (10)
apps/web/app/lib/nodeConfigs/googleSheet.action.ts (3)
apps/web/app/lib/types/node.types.ts (1)
  • NodeConfig (3-22)
apps/web/app/components/nodes/actions.ts (2)
  • updateConfigData (19-27)
  • SaveConfigFormData (4-17)
apps/web/app/components/nodes/GoogleSheetFormClient.tsx (2)
  • config (223-268)
  • GoogleSheetFormClientProps (17-29)
apps/web/app/lib/nodeConfigs/gmail.action.ts (4)
apps/web/app/lib/types/node.types.ts (1)
  • NodeConfig (3-22)
packages/nodes/src/gmail/gmail.node.ts (2)
  • GmailNode (4-43)
  • register (33-38)
packages/nodes/src/gmail/gmail.executor.ts (3)
  • GmailExecutor (17-72)
  • NodeExecutionContext (4-9)
  • execute (25-71)
packages/nodes/src/gmail/gmail.service.ts (3)
  • GmailService (11-111)
  • GmailCredentials (4-9)
  • constructor (14-31)
apps/web/app/components/ui/Design/WorkflowButton.tsx (2)
apps/web/app/components/ui/Design/WorkflowCard.tsx (1)
  • CardDemo (18-126)
apps/web/app/components/ui/Button.tsx (1)
  • props (14-81)
packages/ui/src/components/button.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/worker/src/engine/executor.ts (4)
apps/worker/src/engine/registory.ts (3)
  • execute (11-33)
  • register (7-9)
  • register (47-47)
packages/nodes/src/gmail/gmail.executor.ts (1)
  • execute (25-71)
packages/nodes/src/google-sheets/google-sheets.executor.ts (1)
  • execute (120-170)
packages/db/src/index.ts (1)
  • prismaClient (17-18)
apps/web/app/lib/nodeConfigs/webhook.trigger.ts (1)
apps/web/app/lib/types/node.types.ts (1)
  • NodeConfig (3-22)
apps/web/app/workflows/[id]/page.tsx (5)
apps/web/app/components/NODES/BaseNode.tsx (1)
  • BaseNode (19-164)
apps/web/app/lib/api.ts (1)
  • api (7-71)
apps/web/app/workflows/[id]/components/ConfigModal.tsx (1)
  • ConfigModal (14-174)
apps/web/app/components/nodes/TriggerSidebar.tsx (1)
  • TriggerSideBar (22-66)
apps/web/app/components/Actions/ActionSidebar.tsx (1)
  • ActionSideBar (28-77)
apps/web/app/workflows/[id]/components/ConfigModal.tsx (3)
apps/web/store/slices/userSlice.ts (1)
  • userAction (41-41)
apps/web/app/lib/nodeConfigs/index.ts (1)
  • getNodeConfig (25-27)
packages/nodes/src/google-sheets/token.js (1)
  • code (10-10)
packages/ui/src/components/card.tsx (1)
packages/ui/src/lib/utils.ts (1)
  • cn (4-6)
apps/web/app/page.tsx (1)
apps/web/app/components/ui/Design/WorkflowButton.tsx (1)
  • ParentComponent (7-18)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Agent
🔇 Additional comments (17)
packages/db/prisma/schema.prisma (2)

22-29: LGTM!

The formatting alignment changes improve readability. The commented-out relation is acceptable for tracking schema evolution.


65-66: LGTM!

The position field change from Int to Json supports the new {x, y} coordinate format required by the workflow canvas UI. The new stage field appropriately handles node ordering as an integer.

apps/worker/src/engine/executor.ts (1)

65-76: LGTM!

The output chaining between nodes and the completion status update are correctly implemented.

apps/http-backend/src/routes/userRoutes/userMiddleware.ts (1)

33-42: LGTM!

Good practice to comment out debug logging that could leak sensitive user payload information in production logs.

apps/http-backend/src/routes/userRoutes/userRoutes.ts (1)

50-74: LGTM!

Route formatting improved for readability while maintaining proper authentication.

packages/ui/src/components/button.tsx (1)

1-62: LGTM! Formatting changes applied consistently.

Semicolons have been added throughout the file for style consistency. No functional changes.

packages/ui/src/components/card.tsx (1)

1-92: LGTM! Well-structured card component system.

The card components follow a consistent pattern with proper className merging, data-slot attributes for styling hooks, and clean component composition. Good use of the shared cn utility.

apps/web/app/components/ui/Design/WorkflowButton.tsx (1)

1-17: LGTM on the overall pattern.

The modal toggle pattern using useState is clean, and the conditional rendering approach for the modal is appropriate. The close callback properly resets state.

apps/web/app/lib/nodeConfigs/googleSheet.action.ts (1)

11-49: Consider adding a range field.

The backend node definition (packages/nodes/src/google-sheets/google-sheets.node.ts) and the SaveConfigFormData interface include a range field. Depending on the operations supported, this may be needed for specifying which cells to read/write.

apps/web/app/lib/nodeConfigs/index.ts (1)

1-27: LGTM on the registry pattern.

The centralized registry with lookup by both label and id is a clean approach for node configuration management. The getNodeConfig helper provides a safe fallback with null.

apps/web/app/lib/nodeConfigs/gmail.action.ts (1)

3-49: LGTM on the Gmail action config.

The field names (to, subject, body) align with the GmailExecutor expectations in packages/nodes/src/gmail/gmail.executor.ts. The config structure follows the established NodeConfig pattern correctly.

apps/web/app/lib/types/node.types.ts (2)

3-22: LGTM! Well-structured interface with good documentation.

The NodeConfig interface provides a comprehensive schema for node configurations with appropriate required and optional fields. The inline comments serve as effective documentation.


24-39: LGTM! ConfigField interface covers common form field types.

The interface supports a good variety of field types and includes useful metadata like dependsOn for conditional field visibility.

apps/web/app/lib/nodeConfigs/webhook.trigger.ts (1)

37-49: LGTM! Clean webhook trigger configuration.

The empty fields array with the explanatory comment makes the design intent clear. The configuration correctly implements the NodeConfig interface.

Note: Update helpUrl from the placeholder docs.example.com when real documentation is available.

apps/web/app/components/ui/Design/WorkflowCard.tsx (1)

25-49: Good error handling with appropriate fallbacks.

The error handling logic comprehensively checks multiple error shapes (error.response.data.message, string errors, error.message) with a sensible fallback. The form structure and loading states are well-implemented.

apps/web/app/workflows/[id]/page.tsx (1)

403-415: LGTM on ReactFlow integration.

The ReactFlow canvas setup with custom node types, background, and controls is well-structured. The fitView prop ensures proper initial viewport.

apps/web/app/components/NODES/BaseNode.tsx (1)

36-92: Clean separation between placeholder and configured node rendering.

The conditional rendering based on isPlaceholder is well-structured. Handle placement logic correctly differentiates between trigger (source-only) and action (source + target) nodes for both placeholder and regular states.

Also applies to: 94-163

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +437 to +439
router.put("/workflow/update" , userMiddleware , (req : AuthRequest , res : Response) => {

})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Incomplete route handler will cause requests to hang.

This endpoint has no implementation and returns no response, which will cause client requests to timeout. Either implement the handler or remove it until ready.

🔧 Suggested placeholder implementation
-router.put("/workflow/update" , userMiddleware , (req : AuthRequest , res : Response) => {
-
-})
+router.put("/workflow/update", userMiddleware, async (req: AuthRequest, res: Response) => {
+  // TODO: Implement workflow update logic
+  return res.status(501).json({
+    message: "Not implemented",
+  });
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
router.put("/workflow/update" , userMiddleware , (req : AuthRequest , res : Response) => {
})
router.put("/workflow/update", userMiddleware, async (req: AuthRequest, res: Response) => {
// TODO: Implement workflow update logic
return res.status(501).json({
message: "Not implemented",
});
});
🤖 Prompt for AI Agents
In `@apps/http-backend/src/routes/userRoutes/userRoutes.ts` around lines 437 -
439, The PUT route handler declared as router.put("/workflow/update",
userMiddleware, (req: AuthRequest, res: Response) => { }) is empty and will hang
requests; either implement the handler or remove it. To fix, add a concrete
implementation inside that arrow function: validate req.body, call the
appropriate service/utility (e.g., updateUserWorkflow or whatever existing
workflow update function is used elsewhere), handle errors with try/catch and
return an appropriate response status (200 with updated data or 204 on success,
and 4xx/5xx on errors), or if the feature isn't ready return a clear short
response such as res.status(501). Ensure the handler uses the AuthRequest user
info provided by userMiddleware and always sends a response in all code paths.

@@ -1 +1 @@
{"root":["./src/index.ts","./src/routes/google_callback.ts","./src/routes/nodes.routes.ts","./src/routes/userroutes/usermiddleware.ts","./src/routes/userroutes/userroutes.ts","./src/scheduler/token-scheduler.ts","./src/services/token-refresh.service.ts"],"version":"5.7.3"} No newline at end of file
{"root":["./src/index.ts","./src/routes/google_callback.ts","./src/routes/nodes.routes.ts","./src/routes/userRoutes/userMiddleware.ts","./src/routes/userRoutes/userRoutes.ts","./src/scheduler/token-scheduler.ts","./src/services/token-refresh.service.ts"],"version":"5.7.3"} No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if tsbuildinfo files are ignored in .gitignore
echo "=== Checking .gitignore for tsbuildinfo ==="
if [ -f .gitignore ]; then
  grep -i "tsbuildinfo" .gitignore && echo "Found in .gitignore" || echo "Not found in .gitignore"
else
  echo ".gitignore not found"
fi

# Check for any other tsbuildinfo files in the repo
echo -e "\n=== All tsbuildinfo files in repo ==="
fd -e tsbuildinfo 2>/dev/null || find . -name "*.tsbuildinfo" -type f 2>/dev/null

# Also check if there's a root .gitignore and any nested .gitignore files
echo -e "\n=== All .gitignore files ==="
find . -name ".gitignore" -type f 2>/dev/null

Repository: Dev-Pross/BuildFlow

Length of output: 580


🏁 Script executed:

#!/bin/bash
# Check exact patterns in .gitignore related to tsbuildinfo
echo "=== Content of root .gitignore ==="
cat .gitignore | grep -i tsbuildinfo

echo -e "\n=== Checking git status for tsbuildinfo files ==="
git status --porcelain | grep -i tsbuildinfo || echo "No tsbuildinfo files in git status"

# Check if tsbuildinfo files are tracked by git
echo -e "\n=== Checking if tsbuildinfo files are tracked in git ==="
git ls-files | grep tsbuildinfo || echo "No tracked tsbuildinfo files"

# Check app-level .gitignore files
echo -e "\n=== Checking http-backend .gitignore ==="
if [ -f apps/http-backend/.gitignore ]; then
  cat apps/http-backend/.gitignore | grep -i tsbuildinfo && echo "Found in http-backend/.gitignore" || echo "Not in http-backend/.gitignore"
fi

Repository: Dev-Pross/BuildFlow

Length of output: 733


Remove tsbuildinfo build artifacts from version control and update .gitignore with complete coverage.

tsconfig.tsbuildinfo files are auto-generated incremental build caches that should not be committed. Currently, all tsbuildinfo files are tracked in git despite partial .gitignore entries. Files like apps/hooks/tsconfig.tsbuildinfo, apps/processor/tsconfig.tsbuildinfo, apps/worker/tsconfig.tsbuildinfo, and packages/nodes/tsconfig.tsbuildinfo lack .gitignore coverage entirely.

To resolve: Run git rm --cached on all tracked *.tsbuildinfo files, then ensure the root .gitignore includes a complete pattern such as **/*.tsbuildinfo or individual entries for all affected packages and apps.

🤖 Prompt for AI Agents
In `@apps/http-backend/tsconfig.tsbuildinfo` at line 1, Remove all tracked
TypeScript incremental build artifacts and add a comprehensive ignore rule: run
git rm --cached on every tracked tsbuildinfo file (e.g.,
apps/hooks/tsconfig.tsbuildinfo, apps/processor/tsconfig.tsbuildinfo,
apps/worker/tsconfig.tsbuildinfo, packages/nodes/tsconfig.tsbuildinfo and the
root apps/http-backend/tsconfig.tsbuildinfo) and update the root .gitignore to
include a complete pattern like **/*.tsbuildinfo (or explicit entries for each
package/app) so these autogenerated files are no longer committed.

Comment on lines +36 to +48
{
name: "action",
label: "Action",
type: "dropdown",
options: [
{ label: "Read Rows", value: "read_rows" },
{ label: "Append Row", value: "append_row" },
{ label: "Update Row", value: "update_row" }
],
required: true,
defaultValue: "read_rows",
description: "What operation to perform on the sheet"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Field name mismatch: action vs operation.

The existing codebase interfaces (SaveConfigFormData, updateConfigData in apps/web/app/components/nodes/actions.ts) and the backend node definition use operation, not action. This mismatch will likely cause runtime issues when submitting form data.

🐛 Proposed fix
     {
-      name: "action",
-      label: "Action",
+      name: "operation",
+      label: "Operation",
       type: "dropdown",
       options: [
         { label: "Read Rows", value: "read_rows" },
         { label: "Append Row", value: "append_row" },
         { label: "Update Row", value: "update_row" }
       ],
       required: true,
       defaultValue: "read_rows",
-      description: "What operation to perform on the sheet"
+      description: "What operation to perform on the sheet"
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{
name: "action",
label: "Action",
type: "dropdown",
options: [
{ label: "Read Rows", value: "read_rows" },
{ label: "Append Row", value: "append_row" },
{ label: "Update Row", value: "update_row" }
],
required: true,
defaultValue: "read_rows",
description: "What operation to perform on the sheet"
}
{
name: "operation",
label: "Operation",
type: "dropdown",
options: [
{ label: "Read Rows", value: "read_rows" },
{ label: "Append Row", value: "append_row" },
{ label: "Update Row", value: "update_row" }
],
required: true,
defaultValue: "read_rows",
description: "What operation to perform on the sheet"
}
🤖 Prompt for AI Agents
In `@apps/web/app/lib/nodeConfigs/googleSheet.action.ts` around lines 36 - 48, The
form field name is incorrectly set to "action" in the dropdown config (object
with name: "action"); it must match the rest of the code which expects
"operation". Change the field key from "action" to "operation" in the dropdown
definition (and keep the same options/defaultValue/description) so submitted
data aligns with SaveConfigFormData and updateConfigData; verify any references
to this field in the same module use "operation" as well.

Comment on lines +23 to +24
const userId =userAction.setUserId as unknown as string;
console.log("we are getting this userId from ConfigModal" , userId)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Critical: userAction.setUserId is an action creator, not the user ID value.

userAction.setUserId is a Redux action creator function, not the actual userId string. This code will pass the function reference (or [object Object]) as the userId, which is incorrect.

You need to use a Redux selector (e.g., useSelector) to read the userId from state:

🐛 Proposed fix
 import { getNodeConfig } from "@/app/lib/nodeConfigs";
-import { useState } from "react";
+import { useState } from "react";
+import { useSelector } from "react-redux";
 import { HOOKS_URL } from "@repo/common/zod";
-import { userAction } from "@/store/slices/userSlice";
+// Import the selector for userId from your store
+// import { selectUserId } from "@/store/slices/userSlice";

Then inside the component:

-  const userId = userAction.setUserId as unknown as string;
-  console.log("we are getting this userId from ConfigModal", userId);
+  const userId = useSelector((state: any) => state.user.userId); // adjust selector path as needed
🤖 Prompt for AI Agents
In `@apps/web/app/workflows/`[id]/components/ConfigModal.tsx around lines 23 - 24,
The code is using userAction.setUserId (an action creator) as if it were the
userId; replace this with a Redux selector: import and use useSelector (from
react-redux) to read the userId from state (e.g., call useSelector(state =>
state.user.id) or the existing selector function like selectUserId) inside the
ConfigModal component, remove the incorrect cast of userAction.setUserId, and
update any console/log references to use the selector-derived userId instead of
the action creator reference.

Comment on lines +127 to +145
<div className="space-y-4">
{nodeConfig.fields.map((field) => (
<div key={field.name} className="form-group">
<label className="block text-sm font-medium text-white mb-1">
{field.label}{" "}
{field.required && (
<span className="text-red-400">*</span>
)}
</label>
{/* Render field based on type - only basic input for now */}
<input
type="text"
placeholder={field.placeholder}
className="w-full p-3 border border-gray-900 bg-black text-white rounded-md focus:ring-2 focus:ring-white focus:border-white placeholder-gray-400"
/>
</div>
))}
</div>
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Form inputs are uncontrolled and values are not captured on save.

The dynamically rendered fields have no value or onChange handlers, so user input is lost. The handleSave function (line 29) only passes { HOOKS_URL } regardless of what the user enters.

Consider managing field values in state:

🐛 Proposed fix outline
+const [formValues, setFormValues] = useState<Record<string, any>>({});
+
+const handleFieldChange = (fieldName: string, value: any) => {
+  setFormValues(prev => ({ ...prev, [fieldName]: value }));
+};

 // In handleSave:
-await onSave({ HOOKS_URL }, userId);
+await onSave({ HOOKS_URL, ...formValues }, userId);

 // In the input rendering:
 <input
   type="text"
   placeholder={field.placeholder}
+  value={formValues[field.name] ?? field.defaultValue ?? ""}
+  onChange={(e) => handleFieldChange(field.name, e.target.value)}
   className="w-full p-3 border border-gray-900 bg-black text-white rounded-md..."
 />
🤖 Prompt for AI Agents
In `@apps/web/app/workflows/`[id]/components/ConfigModal.tsx around lines 127 -
145, The form inputs in ConfigModal.tsx are uncontrolled so user edits are lost;
initialize a local state object (e.g., formValues) keyed by nodeConfig.fields'
name (use useState, populated from nodeConfig or default placeholders) and
update it in an onChange handler attached to the rendered <input> for each
field; set each input's value to formValues[field.name]; finally update the call
in handleSave to include the collected formValues (merge with existing HOOKS_URL
behavior) so all dynamic field values are passed back when saving.

Comment on lines +54 to +64
if (!execute.success) {
await prismaClient.workflowExecution.update({
where: { id: workflowExecutionId },
data: {
status: "Failed",
error: execute.error,
completedAt: new Date(),
},
});
return;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Ensure error is serialized to string and log the failing node.

Based on the registry code, execute.error could be an Error object when exceptions are caught. Storing a raw Error object in a string field may result in [object Object]. Additionally, logging which node failed would help debugging.

     if (!execute.success) {
+      const errorMessage = execute.error instanceof Error 
+        ? execute.error.message 
+        : String(execute.error);
+      console.error(`Node "${node.name}" (position ${node.position}) failed: ${errorMessage}`);
       await prismaClient.workflowExecution.update({
         where: { id: workflowExecutionId },
         data: {
           status: "Failed",
-          error: execute.error,
+          error: errorMessage,
           completedAt: new Date(),
         },
       });
       return;
     }
🤖 Prompt for AI Agents
In `@apps/worker/src/engine/executor.ts` around lines 54 - 64, When handling the
failed execute result, ensure the error is serialized to a string before saving
and add the failing node identifier to both the DB update and logs: convert
execute.error to a reliable string (e.g., use execute.error?.message ||
String(execute.error) or JSON.stringify with a fallback) and pass that into
prismaClient.workflowExecution.update for the error field; also include the
current node identifier from the executor scope (e.g., nodeId, currentNode.id or
node.name — whatever symbol is used in this file) as a new field (e.g.,
failedNodeId/failedNodeName) and emit a processLogger or logger call that
records the workflowExecutionId, the failing node identifier, and the serialized
error.

Comment on lines +4 to +5
export const BACKEND_URL = "http://localhost:3002";
export const HOOKS_URL = "http://localhost:3002";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hardcoded localhost URLs will fail in deployed environments.

Both BACKEND_URL and HOOKS_URL are hardcoded to http://localhost:3002. These should be configurable via environment variables for different deployment environments.

🐛 Proposed fix
-export const BACKEND_URL = "http://localhost:3002";
-export const HOOKS_URL = "http://localhost:3002";
+export const BACKEND_URL = process.env.BACKEND_URL ?? "http://localhost:3002";
+export const HOOKS_URL = process.env.HOOKS_URL ?? "http://localhost:3002";

Also, if these URLs will always be the same, consider using a single constant:

export const BACKEND_URL = process.env.BACKEND_URL ?? "http://localhost:3002";
export const HOOKS_URL = BACKEND_URL; // If they're always the same
🤖 Prompt for AI Agents
In `@packages/common/src/index.ts` around lines 4 - 5, BACKEND_URL and HOOKS_URL
are hardcoded to localhost which breaks deployments; change them to read from
environment variables with sensible defaults. Update the constants BACKEND_URL
and HOOKS_URL in packages/common/src/index.ts to use process.env.BACKEND_URL and
process.env.HOOKS_URL (or use BACKEND_URL as the single source if both should
match), falling back to "http://localhost:3002" when the env vars are absent,
and ensure exports remain unchanged so callers keep working.

Comment on lines 28 to 34
export const NodeSchema = z.object({
Name: z.string(),
AvailableNodeId: z.string(),
Config: z.any(),
Position: z.number(),
Config: z.any().optional(),
stage: z.number().optional(),
WorkflowId: z.string(),
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for usages of Position field in node-related code
rg -n -C2 '\bPosition\b' --type ts --type tsx -g '!node_modules'
# Search for stage field usage to verify migration
rg -n -C2 '\.stage\b' --type ts -g '!node_modules'

Repository: Dev-Pross/BuildFlow

Length of output: 597


🏁 Script executed:

#!/bin/bash
# Check the full NodeSchema definition
cat -n packages/common/src/index.ts | sed -n '25,40p'

Repository: Dev-Pross/BuildFlow

Length of output: 529


🏁 Script executed:

#!/bin/bash
# Get more context around the userRoutes.ts line where position appears
cat -n apps/http-backend/src/routes/userRoutes/userRoutes.ts | sed -n '520,540p'

Repository: Dev-Pross/BuildFlow

Length of output: 1031


🏁 Script executed:

#!/bin/bash
# Search for all references to 'position' (lowercase) in node/schema related code
rg -n -C3 '\bposition\b' --type ts -g '!node_modules'

Repository: Dev-Pross/BuildFlow

Length of output: 30850


🏁 Script executed:

#!/bin/bash
# Search for API calls that send Position field
rg -n 'Position\s*:' --type ts -g '!node_modules' -B2 -A2

Repository: Dev-Pross/BuildFlow

Length of output: 1333


Fix incomplete field rename: Positionstage is still referenced in frontend API calls.

The schema was updated to use stage, but frontend code still sends the old Position field name, causing validation failures:

  • apps/web/app/workflows/[id]/page.tsx:226 — Sends Position: 1; should be stage: 1
  • apps/web/app/workflow/lib/config.ts:234 — Sends Position: context.position; should be stage: context.position

The schema validation will reject these requests since NodeSchema expects stage, not Position.

🤖 Prompt for AI Agents
In `@packages/common/src/index.ts` around lines 28 - 34, NodeSchema was renamed to
use stage but frontend still sends Position, causing validation failures; change
the outgoing payload keys so they send stage instead of Position. Specifically,
update the places that currently set "Position: 1" and "Position:
context.position" to use "stage: 1" and "stage: context.position" respectively,
and ensure any related types/objects (payload builders or serialize functions)
that reference Position are updated to stage to match NodeSchema.

Comment on lines +68 to +71
AvailableNodeID String
// CredentialsID String
credentials Credential[]
AvailableNode AvailableNode? @relation(fields: [AvailableNodeID], references: [id])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Inconsistency between required foreign key and optional relation.

AvailableNodeID is defined as String (required/non-nullable), but the AvailableNode relation is marked as optional (AvailableNode?). This is contradictory:

  • If a Node must always have an AvailableNodeID, the relation should be AvailableNode (not optional).
  • If the relation is truly optional, the FK should be String?.

This mismatch can cause confusion in generated types and unexpected behavior.

Suggested fix (if relation should be required)
   AvailableNodeID                           String
-  AvailableNode                             AvailableNode?   `@relation`(fields: [AvailableNodeID], references: [id])
+  AvailableNode                             AvailableNode    `@relation`(fields: [AvailableNodeID], references: [id])
Alternative fix (if relation should be optional)
-  AvailableNodeID                           String
+  AvailableNodeID                           String?
   AvailableNode                             AvailableNode?   `@relation`(fields: [AvailableNodeID], references: [id])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
AvailableNodeID String
// CredentialsID String
credentials Credential[]
AvailableNode AvailableNode? @relation(fields: [AvailableNodeID], references: [id])
AvailableNodeID String
// CredentialsID String
credentials Credential[]
AvailableNode AvailableNode `@relation`(fields: [AvailableNodeID], references: [id])
Suggested change
AvailableNodeID String
// CredentialsID String
credentials Credential[]
AvailableNode AvailableNode? @relation(fields: [AvailableNodeID], references: [id])
AvailableNodeID String?
// CredentialsID String
credentials Credential[]
AvailableNode AvailableNode? `@relation`(fields: [AvailableNodeID], references: [id])
🤖 Prompt for AI Agents
In `@packages/db/prisma/schema.prisma` around lines 68 - 71, AvailableNodeID is
non-nullable but the relation AvailableNode is optional, causing a schema
mismatch; decide intended cardinality and make them consistent: if the relation
must be required, change AvailableNode? to AvailableNode (remove the question
mark) so AvailableNodeID stays String and the relation is required; otherwise,
make the foreign key nullable by changing AvailableNodeID to String? so the
optional relation AvailableNode? aligns with a nullable FK. Update the Prisma
model accordingly and regenerate the client.

Comment on lines +109 to +110
startedAt DateTime @default(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) @db.Timestamptz(6)
completedAt DateTime? @default(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) @db.Timestamptz(6)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

completedAt should not have a default value.

Setting @default(dbgenerated(...)) on completedAt means it will be populated with a timestamp at record creation, even though the execution hasn't completed yet. This breaks the semantic meaning of the field:

  • startedAt with a default is correct (marks when execution record is created/started).
  • completedAt should remain null until the execution actually finishes and be explicitly set by application code.
Suggested fix
   startedAt         DateTime          `@default`(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) `@db.Timestamptz`(6)
-  completedAt       DateTime?         `@default`(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) `@db.Timestamptz`(6)
+  completedAt       DateTime?         `@db.Timestamptz`(6)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
startedAt DateTime @default(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) @db.Timestamptz(6)
completedAt DateTime? @default(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) @db.Timestamptz(6)
startedAt DateTime `@default`(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) `@db.Timestamptz`(6)
completedAt DateTime? `@db.Timestamptz`(6)
🤖 Prompt for AI Agents
In `@packages/db/prisma/schema.prisma` around lines 109 - 110, The completedAt
field currently has a db-generated default which sets a timestamp on creation;
remove the `@default`(dbgenerated("(now() AT TIME ZONE 'utc'::text)")) from the
completedAt field (leave it as DateTime? `@db.Timestamptz`(6) and nullable) so it
stays null until explicitly updated, while keeping startedAt's default intact;
after changing the schema run the Prisma migration to update the DB schema and
ensure application code sets completedAt when the execution finishes.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request refactors user routes and enhances workflow UI components with new node management functionality. The changes introduce a workflow canvas with React Flow, new modal components, and update the database schema to support position-based node layouts.

Changes:

  • Refactored database schema to separate node positioning (Json) from execution ordering (stage Int field)
  • Added new workflow UI components including workflow creation modal, config modal, and placeholder nodes
  • Updated API routes with improved formatting and added position/stage field handling
  • Introduced node configuration system with support for Gmail and Google Sheets integrations

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 37 comments.

Show a summary per file
File Description
packages/ui/src/components/card.tsx New card component for UI consistency
packages/ui/src/components/button.tsx Updated semicolon style for consistency
packages/db/tsconfig.tsbuildinfo TypeScript version updated to 5.9.2
packages/db/src/seed.ts Updated seed data with new position and stage fields
packages/db/prisma/schema.prisma Schema changes: position now Json, added stage Int field, updated NodeExecution timestamps
packages/common/src/index.ts Updated schemas to support optional config and position fields, added HOOKS_URL constant
apps/worker/src/engine/executor.ts Re-enabled error handling and improved logging
apps/web/app/workflows/[id]/page.tsx New workflow canvas page with React Flow integration
apps/web/app/workflows/[id]/components/nodes/PlaceholderNode.tsx New placeholder node component
apps/web/app/workflows/[id]/components/ConfigModal.tsx New configuration modal for nodes
apps/web/app/types/workflow.types.ts Fixed typo in Type field, updated config to optional
apps/web/app/page.tsx Added WorkflowButton component to home page
apps/web/app/lib/types/node.types.ts New type definitions for node configurations
apps/web/app/lib/nodeConfigs/*.ts New node configuration files for webhook, Gmail, and Google Sheets
apps/web/app/lib/api.ts New centralized API client module
apps/web/app/components/ui/Design/WorkflowCard.tsx New workflow creation modal component
apps/web/app/components/ui/Design/WorkflowButton.tsx Button component to trigger workflow creation
apps/web/app/components/nodes/TriggerNode.tsx Updated to support optional icon and config fields
apps/web/app/components/NODES/BaseNode.tsx New unified base node component for workflow canvas
apps/http-backend/tsconfig.tsbuildinfo Updated file paths for userRoutes
apps/http-backend/src/routes/userRoutes/userRoutes.ts Major refactoring with improved formatting, added position/stage support, fixed empty route handler
apps/http-backend/src/routes/userRoutes/userMiddleware.ts Commented out debug log

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

isOpen: boolean;
selectedNode: any | null;
onClose: () => void;
onSave: (config: any, userId: string) => Promise<void>;
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The onSave callback signature expects (config: any, userId: string) as parameters, but in the actual usage in page.tsx (line 425-445), the callback only accepts (nodeId, config). This mismatch will cause runtime errors. The callback signature should be consistent with how it's actually called.

Copilot uses AI. Check for mistakes.
setLoading(true);
try {
// For now, just save empty config
await onSave({ HOOKS_URL }, userId);
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The onSave call passes { HOOKS_URL } as the config and userId as the second parameter, but the actual implementation expects (nodeId, config). This will fail when called. Additionally, HOOKS_URL is a constant string, not a field that should be in curly braces unless you intend to create an object with HOOKS_URL as a key.

Copilot uses AI. Check for mistakes.
} catch (e) {
console.log(
"Error Fetching the credentials ",
e instanceof Error ? e.message : "Unkown reason"
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word "Unkown" is misspelled. It should be "Unknown".

Suggested change
e instanceof Error ? e.message : "Unkown reason"
e instanceof Error ? e.message : "Unknown reason"

Copilot uses AI. Check for mistakes.
TriggerType: trigger.type,
});
const triggerId = result.data.data.id as string;
console.log("The Trigger Id is : ", triggerId);
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug console.log statement should be removed or replaced with proper logging in production code.

Copilot uses AI. Check for mistakes.
);
return res
.status(statusCodes.INTERNAL_SERVER_ERROR)
.json({ message: "Internal server from fetching the credentials" });
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message says "Internal server from fetching the credentials" which is grammatically incorrect. It should be "Internal server error from fetching the credentials" to match the pattern used in other error messages in this file.

Suggested change
.json({ message: "Internal server from fetching the credentials" });
.json({ message: "Internal server error from fetching the credentials" });

Copilot uses AI. Check for mistakes.
// onSelectAction: (action: { id: string; name: string; type: string; icon?: string }) => void;

// 1. Call API to create action in DB
console.log("This is node Id before log", action.id);
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug console.log statements should be removed or replaced with proper logging in production code. This log appears to be debugging code that should be cleaned up.

Copilot uses AI. Check for mistakes.
nodeId String?
node Node? @relation(fields: [nodeId], references: [id])
user User @relation(fields: [userId], references: [id])
// Node_Node_CredentialsIDToCredential Node[] @relation("Node_CredentialsIDToCredential")
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the Node model, there is commented-out code suggesting an incomplete relation design. Remove this commented code or implement the relation properly.

Suggested change
// Node_Node_CredentialsIDToCredential Node[] @relation("Node_CredentialsIDToCredential")

Copilot uses AI. Check for mistakes.
onClose?: () => void;
}

export function CardDemo({ onClose }: CardDemoProps) {
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The component name CardDemo does not reflect its actual purpose. This component creates a workflow modal, so it should be named something like CreateWorkflowModal or WorkflowCreationCard for better clarity.

Copilot uses AI. Check for mistakes.
label,
icon,
isPlaceholder,
config,
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable config.

Suggested change
config,

Copilot uses AI. Check for mistakes.

router.put("/workflow/update" , userMiddleware , (req : AuthRequest , res : Response) => {

})
Copy link

Copilot AI Jan 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid automated semicolon insertion (94% of all statements in the enclosing script have an explicit semicolon).

Suggested change
})
});

Copilot uses AI. Check for mistakes.
@Vamsi-o Vamsi-o merged commit 1c2852d into main Jan 14, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants