From 0e4f10024708d286c82ed2f9fe85c7ec656d898e Mon Sep 17 00:00:00 2001
From: larryro <371767072@qq.com>
Date: Wed, 3 Dec 2025 16:54:50 +0800
Subject: [PATCH 1/3] refactor(workflow): reorganize action helpers into
 /helpers subdirectories

- Move action helper files and types into dedicated /helpers subdirectories
  across multiple workflow action modules:
  - approval/
  - conversation/
  - crawler/
  - imap/
  - integration/
  - rag/
  - website/
  - websitePages/
  - workflow/
  - workflow_processing_records/

- Simplify RAG action interface:
  - Replace documentId/organizationId params with single recordId
  - Remove forceReupload and includeMetadata options
  - Remove explicit timeout parameters from workflow definitions
  - Update upload_text and upload_document operations accordingly

- Update predefined workflow definitions to use new recordId parameter:
  - customer_rag_sync.ts
  - document_rag_sync.ts
  - product_rag_sync.ts
  - website_pages_rag_sync.ts

- Update all import paths across IMAP library files and action modules
- Remove obsolete README documentation files (imap, product, rag)
- Regenerate Convex API type definitions
---
 services/platform/convex/_generated/api.d.ts  | 140 ++++----
 .../node_only/imap/lib/build_email_message.ts |   2 +-
 .../imap/lib/collect_thread_message_ids.ts    |   2 +-
 .../imap/lib/fetch_and_parse_message.ts       |   2 +-
 .../node_only/imap/lib/fetch_email_by_uid.ts  |   2 +-
 .../lib/fetch_messages_from_search_results.ts |   2 +-
 .../node_only/imap/lib/find_root_message.ts   |   2 +-
 .../imap/lib/search_thread_messages.ts        |   2 +-
 .../node_only/imap/retrieve_imap_emails.ts    |   2 +-
 .../predefined_workflows/customer_rag_sync.ts |   3 +-
 .../predefined_workflows/document_rag_sync.ts |   8 +-
 .../predefined_workflows/product_rag_sync.ts  |   3 +-
 .../website_pages_rag_sync.ts                 |   5 +-
 .../actions/approval/approval_action.ts       |  14 +-
 .../approval/{ => helpers}/create_approval.ts |   8 +-
 .../approval/{ => helpers}/get_approval.ts    |   6 +-
 .../{ => helpers}/get_approval_history.ts     |   6 +-
 .../list_approvals_for_execution.ts           |   7 +-
 .../{ => helpers}/list_pending_approvals.ts   |   6 +-
 .../list_pending_approvals_for_execution.ts   |   7 +-
 .../actions/approval/{ => helpers}/types.ts   |   4 +-
 .../{ => helpers}/update_approval_status.ts   |   6 +-
 .../conversation/conversation_action.ts       |  18 +-
 .../helpers/add_message_to_conversation.ts    |   2 +-
 .../helpers/build_conversation_metadata.ts    |   2 +-
 .../helpers/build_email_metadata.ts           |   2 +-
 .../helpers/build_initial_message.ts          |   2 +-
 .../{ => helpers}/create_conversation.ts      |   7 +-
 .../create_conversation_from_email.ts         |  24 +-
 .../create_conversation_from_sent_email.ts    |  81 ++---
 .../find_or_create_customer_from_email.ts     |   2 +-
 .../helpers/find_related_conversation.ts      |   2 +-
 .../{ => helpers}/get_conversation_by_id.ts   |   6 +-
 .../query_conversation_messages.ts            |   7 +-
 .../{ => helpers}/query_conversations.ts      |   7 +-
 .../query_latest_message_by_delivery_state.ts |   7 +-
 .../conversation/{ => helpers}/types.ts       |   2 +-
 .../{ => helpers}/update_conversations.ts     |   7 +-
 .../conversation/helpers/update_message.ts    |   2 +-
 .../actions/crawler/crawler_action.ts         |   2 +-
 .../actions/crawler/{ => helpers}/types.ts    |   1 +
 .../convex/workflow/actions/imap/README.md    | 309 ------------------
 .../{ => helpers}/get_imap_credentials.ts     |   1 +
 .../actions/imap/{ => helpers}/types.ts       |   1 +
 .../workflow/actions/imap/imap_action.ts      |   4 +-
 .../build_secrets_from_integration.ts         |   6 +-
 .../actions/integration/integration_action.ts |   2 +-
 .../convex/workflow/actions/product/README.md | 258 ---------------
 .../convex/workflow/actions/rag/README.md     | 260 ---------------
 .../rag/{ => helpers}/get_document_info.ts    |  43 +--
 .../rag/{ => helpers}/get_rag_config.ts       |   1 +
 .../actions/rag/{ => helpers}/types.ts        |  14 +-
 .../rag/{ => helpers}/upload_file_direct.ts   |  36 +-
 .../rag/{ => helpers}/upload_text_document.ts |  35 +-
 .../convex/workflow/actions/rag/rag_action.ts |  62 ++--
 .../actions/website/{ => helpers}/types.ts    |   0
 .../actions/website/website_action.ts         |   2 +-
 .../websitePages/{ => helpers}/types.ts       |   1 +
 .../websitePages/websitePages_action.ts       |   2 +-
 .../actions/workflow/{ => helpers}/types.ts   |   1 +
 .../{ => helpers}/upload_workflows.ts         |  21 +-
 .../actions/workflow/workflow_action.ts       |   4 +-
 .../find_product_recommendation_by_status.ts  |   7 +-
 .../{ => helpers}/find_unprocessed.ts         |   5 +-
 .../find_unprocessed_open_conversation.ts     |   5 +-
 .../{ => helpers}/record_processed.ts         |   7 +-
 .../{ => helpers}/types.ts                    |   3 +-
 .../workflow_processing_records_action.ts     |  10 +-
 68 files changed, 352 insertions(+), 1170 deletions(-)
 rename services/platform/convex/workflow/actions/approval/{ => helpers}/create_approval.ts (80%)
 rename services/platform/convex/workflow/actions/approval/{ => helpers}/get_approval.ts (67%)
 rename services/platform/convex/workflow/actions/approval/{ => helpers}/get_approval_history.ts (81%)
 rename services/platform/convex/workflow/actions/approval/{ => helpers}/list_approvals_for_execution.ts (72%)
 rename services/platform/convex/workflow/actions/approval/{ => helpers}/list_pending_approvals.ts (83%)
 rename services/platform/convex/workflow/actions/approval/{ => helpers}/list_pending_approvals_for_execution.ts (73%)
 rename services/platform/convex/workflow/actions/approval/{ => helpers}/types.ts (91%)
 rename services/platform/convex/workflow/actions/approval/{ => helpers}/update_approval_status.ts (78%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/create_conversation.ts (85%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/create_conversation_from_email.ts (91%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/create_conversation_from_sent_email.ts (87%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/get_conversation_by_id.ts (69%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/query_conversation_messages.ts (82%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/query_conversations.ts (84%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/query_latest_message_by_delivery_state.ts (80%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/types.ts (93%)
 rename services/platform/convex/workflow/actions/conversation/{ => helpers}/update_conversations.ts (82%)
 rename services/platform/convex/workflow/actions/crawler/{ => helpers}/types.ts (99%)
 delete mode 100644 services/platform/convex/workflow/actions/imap/README.md
 rename services/platform/convex/workflow/actions/imap/{ => helpers}/get_imap_credentials.ts (99%)
 rename services/platform/convex/workflow/actions/imap/{ => helpers}/types.ts (99%)
 rename services/platform/convex/workflow/actions/integration/{ => helpers}/build_secrets_from_integration.ts (86%)
 delete mode 100644 services/platform/convex/workflow/actions/product/README.md
 delete mode 100644 services/platform/convex/workflow/actions/rag/README.md
 rename services/platform/convex/workflow/actions/rag/{ => helpers}/get_document_info.ts (59%)
 rename services/platform/convex/workflow/actions/rag/{ => helpers}/get_rag_config.ts (99%)
 rename services/platform/convex/workflow/actions/rag/{ => helpers}/types.ts (84%)
 rename services/platform/convex/workflow/actions/rag/{ => helpers}/upload_file_direct.ts (77%)
 rename services/platform/convex/workflow/actions/rag/{ => helpers}/upload_text_document.ts (64%)
 rename services/platform/convex/workflow/actions/website/{ => helpers}/types.ts (100%)
 rename services/platform/convex/workflow/actions/websitePages/{ => helpers}/types.ts (99%)
 rename services/platform/convex/workflow/actions/workflow/{ => helpers}/types.ts (99%)
 rename services/platform/convex/workflow/actions/workflow/{ => helpers}/upload_workflows.ts (84%)
 rename services/platform/convex/workflow/actions/workflow_processing_records/{ => helpers}/find_product_recommendation_by_status.ts (80%)
 rename services/platform/convex/workflow/actions/workflow_processing_records/{ => helpers}/find_unprocessed.ts (83%)
 rename services/platform/convex/workflow/actions/workflow_processing_records/{ => helpers}/find_unprocessed_open_conversation.ts (83%)
 rename services/platform/convex/workflow/actions/workflow_processing_records/{ => helpers}/record_processed.ts (82%)
 rename services/platform/convex/workflow/actions/workflow_processing_records/{ => helpers}/types.ts (87%)

diff --git a/services/platform/convex/_generated/api.d.ts b/services/platform/convex/_generated/api.d.ts
index b4b47790f8..8ed5292afe 100644
--- a/services/platform/convex/_generated/api.d.ts
+++ b/services/platform/convex/_generated/api.d.ts
@@ -458,65 +458,65 @@ import type * as wf_executions from "../wf_executions.js";
 import type * as wf_step_defs from "../wf_step_defs.js";
 import type * as workflow_actions_action_registry from "../workflow/actions/action_registry.js";
 import type * as workflow_actions_approval_approval_action from "../workflow/actions/approval/approval_action.js";
-import type * as workflow_actions_approval_create_approval from "../workflow/actions/approval/create_approval.js";
-import type * as workflow_actions_approval_get_approval from "../workflow/actions/approval/get_approval.js";
-import type * as workflow_actions_approval_get_approval_history from "../workflow/actions/approval/get_approval_history.js";
-import type * as workflow_actions_approval_list_approvals_for_execution from "../workflow/actions/approval/list_approvals_for_execution.js";
-import type * as workflow_actions_approval_list_pending_approvals from "../workflow/actions/approval/list_pending_approvals.js";
-import type * as workflow_actions_approval_list_pending_approvals_for_execution from "../workflow/actions/approval/list_pending_approvals_for_execution.js";
-import type * as workflow_actions_approval_types from "../workflow/actions/approval/types.js";
-import type * as workflow_actions_approval_update_approval_status from "../workflow/actions/approval/update_approval_status.js";
+import type * as workflow_actions_approval_helpers_create_approval from "../workflow/actions/approval/helpers/create_approval.js";
+import type * as workflow_actions_approval_helpers_get_approval from "../workflow/actions/approval/helpers/get_approval.js";
+import type * as workflow_actions_approval_helpers_get_approval_history from "../workflow/actions/approval/helpers/get_approval_history.js";
+import type * as workflow_actions_approval_helpers_list_approvals_for_execution from "../workflow/actions/approval/helpers/list_approvals_for_execution.js";
+import type * as workflow_actions_approval_helpers_list_pending_approvals from "../workflow/actions/approval/helpers/list_pending_approvals.js";
+import type * as workflow_actions_approval_helpers_list_pending_approvals_for_execution from "../workflow/actions/approval/helpers/list_pending_approvals_for_execution.js";
+import type * as workflow_actions_approval_helpers_types from "../workflow/actions/approval/helpers/types.js";
+import type * as workflow_actions_approval_helpers_update_approval_status from "../workflow/actions/approval/helpers/update_approval_status.js";
 import type * as workflow_actions_conversation_conversation_action from "../workflow/actions/conversation/conversation_action.js";
-import type * as workflow_actions_conversation_create_conversation from "../workflow/actions/conversation/create_conversation.js";
-import type * as workflow_actions_conversation_create_conversation_from_email from "../workflow/actions/conversation/create_conversation_from_email.js";
-import type * as workflow_actions_conversation_create_conversation_from_sent_email from "../workflow/actions/conversation/create_conversation_from_sent_email.js";
-import type * as workflow_actions_conversation_get_conversation_by_id from "../workflow/actions/conversation/get_conversation_by_id.js";
 import type * as workflow_actions_conversation_helpers_add_message_to_conversation from "../workflow/actions/conversation/helpers/add_message_to_conversation.js";
 import type * as workflow_actions_conversation_helpers_build_conversation_metadata from "../workflow/actions/conversation/helpers/build_conversation_metadata.js";
 import type * as workflow_actions_conversation_helpers_build_email_metadata from "../workflow/actions/conversation/helpers/build_email_metadata.js";
 import type * as workflow_actions_conversation_helpers_build_initial_message from "../workflow/actions/conversation/helpers/build_initial_message.js";
 import type * as workflow_actions_conversation_helpers_check_conversation_exists from "../workflow/actions/conversation/helpers/check_conversation_exists.js";
 import type * as workflow_actions_conversation_helpers_check_message_exists from "../workflow/actions/conversation/helpers/check_message_exists.js";
+import type * as workflow_actions_conversation_helpers_create_conversation from "../workflow/actions/conversation/helpers/create_conversation.js";
+import type * as workflow_actions_conversation_helpers_create_conversation_from_email from "../workflow/actions/conversation/helpers/create_conversation_from_email.js";
+import type * as workflow_actions_conversation_helpers_create_conversation_from_sent_email from "../workflow/actions/conversation/helpers/create_conversation_from_sent_email.js";
 import type * as workflow_actions_conversation_helpers_find_or_create_customer_from_email from "../workflow/actions/conversation/helpers/find_or_create_customer_from_email.js";
 import type * as workflow_actions_conversation_helpers_find_related_conversation from "../workflow/actions/conversation/helpers/find_related_conversation.js";
+import type * as workflow_actions_conversation_helpers_get_conversation_by_id from "../workflow/actions/conversation/helpers/get_conversation_by_id.js";
+import type * as workflow_actions_conversation_helpers_query_conversation_messages from "../workflow/actions/conversation/helpers/query_conversation_messages.js";
+import type * as workflow_actions_conversation_helpers_query_conversations from "../workflow/actions/conversation/helpers/query_conversations.js";
+import type * as workflow_actions_conversation_helpers_query_latest_message_by_delivery_state from "../workflow/actions/conversation/helpers/query_latest_message_by_delivery_state.js";
+import type * as workflow_actions_conversation_helpers_types from "../workflow/actions/conversation/helpers/types.js";
+import type * as workflow_actions_conversation_helpers_update_conversations from "../workflow/actions/conversation/helpers/update_conversations.js";
 import type * as workflow_actions_conversation_helpers_update_message from "../workflow/actions/conversation/helpers/update_message.js";
-import type * as workflow_actions_conversation_query_conversation_messages from "../workflow/actions/conversation/query_conversation_messages.js";
-import type * as workflow_actions_conversation_query_conversations from "../workflow/actions/conversation/query_conversations.js";
-import type * as workflow_actions_conversation_query_latest_message_by_delivery_state from "../workflow/actions/conversation/query_latest_message_by_delivery_state.js";
-import type * as workflow_actions_conversation_types from "../workflow/actions/conversation/types.js";
-import type * as workflow_actions_conversation_update_conversations from "../workflow/actions/conversation/update_conversations.js";
 import type * as workflow_actions_crawler_crawler_action from "../workflow/actions/crawler/crawler_action.js";
-import type * as workflow_actions_crawler_types from "../workflow/actions/crawler/types.js";
+import type * as workflow_actions_crawler_helpers_types from "../workflow/actions/crawler/helpers/types.js";
 import type * as workflow_actions_customer_customer_action from "../workflow/actions/customer/customer_action.js";
 import type * as workflow_actions_document_document_action from "../workflow/actions/document/document_action.js";
 import type * as workflow_actions_email_provider_email_provider_action from "../workflow/actions/email_provider/email_provider_action.js";
-import type * as workflow_actions_imap_get_imap_credentials from "../workflow/actions/imap/get_imap_credentials.js";
+import type * as workflow_actions_imap_helpers_get_imap_credentials from "../workflow/actions/imap/helpers/get_imap_credentials.js";
+import type * as workflow_actions_imap_helpers_types from "../workflow/actions/imap/helpers/types.js";
 import type * as workflow_actions_imap_imap_action from "../workflow/actions/imap/imap_action.js";
-import type * as workflow_actions_imap_types from "../workflow/actions/imap/types.js";
-import type * as workflow_actions_integration_build_secrets_from_integration from "../workflow/actions/integration/build_secrets_from_integration.js";
+import type * as workflow_actions_integration_helpers_build_secrets_from_integration from "../workflow/actions/integration/helpers/build_secrets_from_integration.js";
 import type * as workflow_actions_integration_integration_action from "../workflow/actions/integration/integration_action.js";
 import type * as workflow_actions_onedrive_onedrive_action from "../workflow/actions/onedrive/onedrive_action.js";
 import type * as workflow_actions_product_product_action from "../workflow/actions/product/product_action.js";
-import type * as workflow_actions_rag_get_document_info from "../workflow/actions/rag/get_document_info.js";
-import type * as workflow_actions_rag_get_rag_config from "../workflow/actions/rag/get_rag_config.js";
+import type * as workflow_actions_rag_helpers_get_document_info from "../workflow/actions/rag/helpers/get_document_info.js";
+import type * as workflow_actions_rag_helpers_get_rag_config from "../workflow/actions/rag/helpers/get_rag_config.js";
+import type * as workflow_actions_rag_helpers_types from "../workflow/actions/rag/helpers/types.js";
+import type * as workflow_actions_rag_helpers_upload_file_direct from "../workflow/actions/rag/helpers/upload_file_direct.js";
+import type * as workflow_actions_rag_helpers_upload_text_document from "../workflow/actions/rag/helpers/upload_text_document.js";
 import type * as workflow_actions_rag_rag_action from "../workflow/actions/rag/rag_action.js";
-import type * as workflow_actions_rag_types from "../workflow/actions/rag/types.js";
-import type * as workflow_actions_rag_upload_file_direct from "../workflow/actions/rag/upload_file_direct.js";
-import type * as workflow_actions_rag_upload_text_document from "../workflow/actions/rag/upload_text_document.js";
 import type * as workflow_actions_set_variables_action from "../workflow/actions/set_variables_action.js";
 import type * as workflow_actions_tone_of_voice_tone_of_voice_action from "../workflow/actions/tone_of_voice/tone_of_voice_action.js";
-import type * as workflow_actions_website_types from "../workflow/actions/website/types.js";
+import type * as workflow_actions_website_helpers_types from "../workflow/actions/website/helpers/types.js";
 import type * as workflow_actions_website_website_action from "../workflow/actions/website/website_action.js";
-import type * as workflow_actions_websitePages_types from "../workflow/actions/websitePages/types.js";
+import type * as workflow_actions_websitePages_helpers_types from "../workflow/actions/websitePages/helpers/types.js";
 import type * as workflow_actions_websitePages_websitePages_action from "../workflow/actions/websitePages/websitePages_action.js";
-import type * as workflow_actions_workflow_types from "../workflow/actions/workflow/types.js";
-import type * as workflow_actions_workflow_upload_workflows from "../workflow/actions/workflow/upload_workflows.js";
+import type * as workflow_actions_workflow_helpers_types from "../workflow/actions/workflow/helpers/types.js";
+import type * as workflow_actions_workflow_helpers_upload_workflows from "../workflow/actions/workflow/helpers/upload_workflows.js";
 import type * as workflow_actions_workflow_workflow_action from "../workflow/actions/workflow/workflow_action.js";
-import type * as workflow_actions_workflow_processing_records_find_product_recommendation_by_status from "../workflow/actions/workflow_processing_records/find_product_recommendation_by_status.js";
-import type * as workflow_actions_workflow_processing_records_find_unprocessed from "../workflow/actions/workflow_processing_records/find_unprocessed.js";
-import type * as workflow_actions_workflow_processing_records_find_unprocessed_open_conversation from "../workflow/actions/workflow_processing_records/find_unprocessed_open_conversation.js";
-import type * as workflow_actions_workflow_processing_records_record_processed from "../workflow/actions/workflow_processing_records/record_processed.js";
-import type * as workflow_actions_workflow_processing_records_types from "../workflow/actions/workflow_processing_records/types.js";
+import type * as workflow_actions_workflow_processing_records_helpers_find_product_recommendation_by_status from "../workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status.js";
+import type * as workflow_actions_workflow_processing_records_helpers_find_unprocessed from "../workflow/actions/workflow_processing_records/helpers/find_unprocessed.js";
+import type * as workflow_actions_workflow_processing_records_helpers_find_unprocessed_open_conversation from "../workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation.js";
+import type * as workflow_actions_workflow_processing_records_helpers_record_processed from "../workflow/actions/workflow_processing_records/helpers/record_processed.js";
+import type * as workflow_actions_workflow_processing_records_helpers_types from "../workflow/actions/workflow_processing_records/helpers/types.js";
 import type * as workflow_actions_workflow_processing_records_workflow_processing_records_action from "../workflow/actions/workflow_processing_records/workflow_processing_records_action.js";
 import type * as workflow_engine from "../workflow/engine.js";
 import type * as workflow_helpers_data_source_database_workflow_data_source from "../workflow/helpers/data_source/database_workflow_data_source.js";
@@ -1049,65 +1049,65 @@ declare const fullApi: ApiFromModules<{
   wf_step_defs: typeof wf_step_defs;
   "workflow/actions/action_registry": typeof workflow_actions_action_registry;
   "workflow/actions/approval/approval_action": typeof workflow_actions_approval_approval_action;
-  "workflow/actions/approval/create_approval": typeof workflow_actions_approval_create_approval;
-  "workflow/actions/approval/get_approval": typeof workflow_actions_approval_get_approval;
-  "workflow/actions/approval/get_approval_history": typeof workflow_actions_approval_get_approval_history;
-  "workflow/actions/approval/list_approvals_for_execution": typeof workflow_actions_approval_list_approvals_for_execution;
-  "workflow/actions/approval/list_pending_approvals": typeof workflow_actions_approval_list_pending_approvals;
-  "workflow/actions/approval/list_pending_approvals_for_execution": typeof workflow_actions_approval_list_pending_approvals_for_execution;
-  "workflow/actions/approval/types": typeof workflow_actions_approval_types;
-  "workflow/actions/approval/update_approval_status": typeof workflow_actions_approval_update_approval_status;
+  "workflow/actions/approval/helpers/create_approval": typeof workflow_actions_approval_helpers_create_approval;
+  "workflow/actions/approval/helpers/get_approval": typeof workflow_actions_approval_helpers_get_approval;
+  "workflow/actions/approval/helpers/get_approval_history": typeof workflow_actions_approval_helpers_get_approval_history;
+  "workflow/actions/approval/helpers/list_approvals_for_execution": typeof workflow_actions_approval_helpers_list_approvals_for_execution;
+  "workflow/actions/approval/helpers/list_pending_approvals": typeof workflow_actions_approval_helpers_list_pending_approvals;
+  "workflow/actions/approval/helpers/list_pending_approvals_for_execution": typeof workflow_actions_approval_helpers_list_pending_approvals_for_execution;
+  "workflow/actions/approval/helpers/types": typeof workflow_actions_approval_helpers_types;
+  "workflow/actions/approval/helpers/update_approval_status": typeof workflow_actions_approval_helpers_update_approval_status;
   "workflow/actions/conversation/conversation_action": typeof workflow_actions_conversation_conversation_action;
-  "workflow/actions/conversation/create_conversation": typeof workflow_actions_conversation_create_conversation;
-  "workflow/actions/conversation/create_conversation_from_email": typeof workflow_actions_conversation_create_conversation_from_email;
-  "workflow/actions/conversation/create_conversation_from_sent_email": typeof workflow_actions_conversation_create_conversation_from_sent_email;
-  "workflow/actions/conversation/get_conversation_by_id": typeof workflow_actions_conversation_get_conversation_by_id;
   "workflow/actions/conversation/helpers/add_message_to_conversation": typeof workflow_actions_conversation_helpers_add_message_to_conversation;
   "workflow/actions/conversation/helpers/build_conversation_metadata": typeof workflow_actions_conversation_helpers_build_conversation_metadata;
   "workflow/actions/conversation/helpers/build_email_metadata": typeof workflow_actions_conversation_helpers_build_email_metadata;
   "workflow/actions/conversation/helpers/build_initial_message": typeof workflow_actions_conversation_helpers_build_initial_message;
   "workflow/actions/conversation/helpers/check_conversation_exists": typeof workflow_actions_conversation_helpers_check_conversation_exists;
   "workflow/actions/conversation/helpers/check_message_exists": typeof workflow_actions_conversation_helpers_check_message_exists;
+  "workflow/actions/conversation/helpers/create_conversation": typeof workflow_actions_conversation_helpers_create_conversation;
+  "workflow/actions/conversation/helpers/create_conversation_from_email": typeof workflow_actions_conversation_helpers_create_conversation_from_email;
+  "workflow/actions/conversation/helpers/create_conversation_from_sent_email": typeof workflow_actions_conversation_helpers_create_conversation_from_sent_email;
   "workflow/actions/conversation/helpers/find_or_create_customer_from_email": typeof workflow_actions_conversation_helpers_find_or_create_customer_from_email;
   "workflow/actions/conversation/helpers/find_related_conversation": typeof workflow_actions_conversation_helpers_find_related_conversation;
+  "workflow/actions/conversation/helpers/get_conversation_by_id": typeof workflow_actions_conversation_helpers_get_conversation_by_id;
+  "workflow/actions/conversation/helpers/query_conversation_messages": typeof workflow_actions_conversation_helpers_query_conversation_messages;
+  "workflow/actions/conversation/helpers/query_conversations": typeof workflow_actions_conversation_helpers_query_conversations;
+  "workflow/actions/conversation/helpers/query_latest_message_by_delivery_state": typeof workflow_actions_conversation_helpers_query_latest_message_by_delivery_state;
+  "workflow/actions/conversation/helpers/types": typeof workflow_actions_conversation_helpers_types;
+  "workflow/actions/conversation/helpers/update_conversations": typeof workflow_actions_conversation_helpers_update_conversations;
   "workflow/actions/conversation/helpers/update_message": typeof workflow_actions_conversation_helpers_update_message;
-  "workflow/actions/conversation/query_conversation_messages": typeof workflow_actions_conversation_query_conversation_messages;
-  "workflow/actions/conversation/query_conversations": typeof workflow_actions_conversation_query_conversations;
-  "workflow/actions/conversation/query_latest_message_by_delivery_state": typeof workflow_actions_conversation_query_latest_message_by_delivery_state;
-  "workflow/actions/conversation/types": typeof workflow_actions_conversation_types;
-  "workflow/actions/conversation/update_conversations": typeof workflow_actions_conversation_update_conversations;
   "workflow/actions/crawler/crawler_action": typeof workflow_actions_crawler_crawler_action;
-  "workflow/actions/crawler/types": typeof workflow_actions_crawler_types;
+  "workflow/actions/crawler/helpers/types": typeof workflow_actions_crawler_helpers_types;
   "workflow/actions/customer/customer_action": typeof workflow_actions_customer_customer_action;
   "workflow/actions/document/document_action": typeof workflow_actions_document_document_action;
   "workflow/actions/email_provider/email_provider_action": typeof workflow_actions_email_provider_email_provider_action;
-  "workflow/actions/imap/get_imap_credentials": typeof workflow_actions_imap_get_imap_credentials;
+  "workflow/actions/imap/helpers/get_imap_credentials": typeof workflow_actions_imap_helpers_get_imap_credentials;
+  "workflow/actions/imap/helpers/types": typeof workflow_actions_imap_helpers_types;
   "workflow/actions/imap/imap_action": typeof workflow_actions_imap_imap_action;
-  "workflow/actions/imap/types": typeof workflow_actions_imap_types;
-  "workflow/actions/integration/build_secrets_from_integration": typeof workflow_actions_integration_build_secrets_from_integration;
+  "workflow/actions/integration/helpers/build_secrets_from_integration": typeof workflow_actions_integration_helpers_build_secrets_from_integration;
   "workflow/actions/integration/integration_action": typeof workflow_actions_integration_integration_action;
   "workflow/actions/onedrive/onedrive_action": typeof workflow_actions_onedrive_onedrive_action;
   "workflow/actions/product/product_action": typeof workflow_actions_product_product_action;
-  "workflow/actions/rag/get_document_info": typeof workflow_actions_rag_get_document_info;
-  "workflow/actions/rag/get_rag_config": typeof workflow_actions_rag_get_rag_config;
+  "workflow/actions/rag/helpers/get_document_info": typeof workflow_actions_rag_helpers_get_document_info;
+  "workflow/actions/rag/helpers/get_rag_config": typeof workflow_actions_rag_helpers_get_rag_config;
+  "workflow/actions/rag/helpers/types": typeof workflow_actions_rag_helpers_types;
+  "workflow/actions/rag/helpers/upload_file_direct": typeof workflow_actions_rag_helpers_upload_file_direct;
+  "workflow/actions/rag/helpers/upload_text_document": typeof workflow_actions_rag_helpers_upload_text_document;
   "workflow/actions/rag/rag_action": typeof workflow_actions_rag_rag_action;
-  "workflow/actions/rag/types": typeof workflow_actions_rag_types;
-  "workflow/actions/rag/upload_file_direct": typeof workflow_actions_rag_upload_file_direct;
-  "workflow/actions/rag/upload_text_document": typeof workflow_actions_rag_upload_text_document;
   "workflow/actions/set_variables_action": typeof workflow_actions_set_variables_action;
   "workflow/actions/tone_of_voice/tone_of_voice_action": typeof workflow_actions_tone_of_voice_tone_of_voice_action;
-  "workflow/actions/website/types": typeof workflow_actions_website_types;
+  "workflow/actions/website/helpers/types": typeof workflow_actions_website_helpers_types;
   "workflow/actions/website/website_action": typeof workflow_actions_website_website_action;
-  "workflow/actions/websitePages/types": typeof workflow_actions_websitePages_types;
+  "workflow/actions/websitePages/helpers/types": typeof workflow_actions_websitePages_helpers_types;
   "workflow/actions/websitePages/websitePages_action": typeof workflow_actions_websitePages_websitePages_action;
-  "workflow/actions/workflow/types": typeof workflow_actions_workflow_types;
-  "workflow/actions/workflow/upload_workflows": typeof workflow_actions_workflow_upload_workflows;
+  "workflow/actions/workflow/helpers/types": typeof workflow_actions_workflow_helpers_types;
+  "workflow/actions/workflow/helpers/upload_workflows": typeof workflow_actions_workflow_helpers_upload_workflows;
   "workflow/actions/workflow/workflow_action": typeof workflow_actions_workflow_workflow_action;
-  "workflow/actions/workflow_processing_records/find_product_recommendation_by_status": typeof workflow_actions_workflow_processing_records_find_product_recommendation_by_status;
-  "workflow/actions/workflow_processing_records/find_unprocessed": typeof workflow_actions_workflow_processing_records_find_unprocessed;
-  "workflow/actions/workflow_processing_records/find_unprocessed_open_conversation": typeof workflow_actions_workflow_processing_records_find_unprocessed_open_conversation;
-  "workflow/actions/workflow_processing_records/record_processed": typeof workflow_actions_workflow_processing_records_record_processed;
-  "workflow/actions/workflow_processing_records/types": typeof workflow_actions_workflow_processing_records_types;
+  "workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status": typeof workflow_actions_workflow_processing_records_helpers_find_product_recommendation_by_status;
+  "workflow/actions/workflow_processing_records/helpers/find_unprocessed": typeof workflow_actions_workflow_processing_records_helpers_find_unprocessed;
+  "workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation": typeof workflow_actions_workflow_processing_records_helpers_find_unprocessed_open_conversation;
+  "workflow/actions/workflow_processing_records/helpers/record_processed": typeof workflow_actions_workflow_processing_records_helpers_record_processed;
+  "workflow/actions/workflow_processing_records/helpers/types": typeof workflow_actions_workflow_processing_records_helpers_types;
   "workflow/actions/workflow_processing_records/workflow_processing_records_action": typeof workflow_actions_workflow_processing_records_workflow_processing_records_action;
   "workflow/engine": typeof workflow_engine;
   "workflow/helpers/data_source/database_workflow_data_source": typeof workflow_helpers_data_source_database_workflow_data_source;
diff --git a/services/platform/convex/node_only/imap/lib/build_email_message.ts b/services/platform/convex/node_only/imap/lib/build_email_message.ts
index a9bebc7595..da0f93c889 100644
--- a/services/platform/convex/node_only/imap/lib/build_email_message.ts
+++ b/services/platform/convex/node_only/imap/lib/build_email_message.ts
@@ -1,7 +1,7 @@
 'use node';
 
 import type { ParsedMail } from 'mailparser';
-import type { EmailMessage } from '../../../workflow/actions/imap/types';
+import type { EmailMessage } from '../../../workflow/actions/imap/helpers/types';
 import extractAddresses from './addresses';
 import parseHeaders from './parse_headers';
 
diff --git a/services/platform/convex/node_only/imap/lib/collect_thread_message_ids.ts b/services/platform/convex/node_only/imap/lib/collect_thread_message_ids.ts
index 5751a4fa2d..49a940d200 100644
--- a/services/platform/convex/node_only/imap/lib/collect_thread_message_ids.ts
+++ b/services/platform/convex/node_only/imap/lib/collect_thread_message_ids.ts
@@ -1,6 +1,6 @@
 'use node';
 
-import type { EmailMessage } from '../../../workflow/actions/imap/types';
+import type { EmailMessage } from '../../../workflow/actions/imap/helpers/types';
 import extractThreadMessageIds from './extract_thread_message_ids';
 
 export default function collectThreadMessageIds(
diff --git a/services/platform/convex/node_only/imap/lib/fetch_and_parse_message.ts b/services/platform/convex/node_only/imap/lib/fetch_and_parse_message.ts
index 1f4b372dc1..83bce42bc4 100644
--- a/services/platform/convex/node_only/imap/lib/fetch_and_parse_message.ts
+++ b/services/platform/convex/node_only/imap/lib/fetch_and_parse_message.ts
@@ -2,7 +2,7 @@
 
 import type { ImapFlow } from 'imapflow';
 import { simpleParser } from 'mailparser';
-import type { EmailMessage } from '../../../workflow/actions/imap/types';
+import type { EmailMessage } from '../../../workflow/actions/imap/helpers/types';
 
 import { createDebugLog } from '../../../lib/debug_log';
 import buildEmailMessage from './build_email_message';
diff --git a/services/platform/convex/node_only/imap/lib/fetch_email_by_uid.ts b/services/platform/convex/node_only/imap/lib/fetch_email_by_uid.ts
index f307c7c18c..6c0b8afdef 100644
--- a/services/platform/convex/node_only/imap/lib/fetch_email_by_uid.ts
+++ b/services/platform/convex/node_only/imap/lib/fetch_email_by_uid.ts
@@ -3,7 +3,7 @@
 import type { ImapFlow } from 'imapflow';
 import { simpleParser, type ParsedMail } from 'mailparser';
 import extractAddresses from './addresses';
-import type { EmailMessage } from '../../../workflow/actions/imap/types';
+import type { EmailMessage } from '../../../workflow/actions/imap/helpers/types';
 
 export interface FetchOptions {
   includeAttachments: boolean;
diff --git a/services/platform/convex/node_only/imap/lib/fetch_messages_from_search_results.ts b/services/platform/convex/node_only/imap/lib/fetch_messages_from_search_results.ts
index 5ab5329eb3..e9069be439 100644
--- a/services/platform/convex/node_only/imap/lib/fetch_messages_from_search_results.ts
+++ b/services/platform/convex/node_only/imap/lib/fetch_messages_from_search_results.ts
@@ -1,7 +1,7 @@
 'use node';
 
 import type { ImapFlow } from 'imapflow';
-import type { EmailMessage } from '../../../workflow/actions/imap/types';
+import type { EmailMessage } from '../../../workflow/actions/imap/helpers/types';
 import type { SearchResult } from './find_message_in_folders';
 import fetchAndParseMessage from './fetch_and_parse_message';
 
diff --git a/services/platform/convex/node_only/imap/lib/find_root_message.ts b/services/platform/convex/node_only/imap/lib/find_root_message.ts
index 5cd9cb58f3..1af8ac36d0 100644
--- a/services/platform/convex/node_only/imap/lib/find_root_message.ts
+++ b/services/platform/convex/node_only/imap/lib/find_root_message.ts
@@ -1,6 +1,6 @@
 'use node';
 
-import type { EmailMessage } from '../../../workflow/actions/imap/types';
+import type { EmailMessage } from '../../../workflow/actions/imap/helpers/types';
 
 import { createDebugLog } from '../../../lib/debug_log';
 
diff --git a/services/platform/convex/node_only/imap/lib/search_thread_messages.ts b/services/platform/convex/node_only/imap/lib/search_thread_messages.ts
index cbbd7fdb26..f3f5d6e8ed 100644
--- a/services/platform/convex/node_only/imap/lib/search_thread_messages.ts
+++ b/services/platform/convex/node_only/imap/lib/search_thread_messages.ts
@@ -1,7 +1,7 @@
 'use node';
 
 import type { ImapFlow } from 'imapflow';
-import type { EmailMessage } from '../../../workflow/actions/imap/types';
+import type { EmailMessage } from '../../../workflow/actions/imap/helpers/types';
 
 import { createDebugLog } from '../../../lib/debug_log';
 import collectThreadMessageIds from './collect_thread_message_ids';
diff --git a/services/platform/convex/node_only/imap/retrieve_imap_emails.ts b/services/platform/convex/node_only/imap/retrieve_imap_emails.ts
index ce048d3a90..ca55c5b3da 100644
--- a/services/platform/convex/node_only/imap/retrieve_imap_emails.ts
+++ b/services/platform/convex/node_only/imap/retrieve_imap_emails.ts
@@ -3,7 +3,7 @@
 import { ImapFlow } from 'imapflow';
 import { internalAction } from '../../_generated/server';
 import { v } from 'convex/values';
-import type { EmailMessage } from '../../workflow/actions/imap/types';
+import type { EmailMessage } from '../../workflow/actions/imap/helpers/types';
 
 import { createDebugLog } from '../../lib/debug_log';
 import computeUidToFetch from './lib/compute_uids_to_fetch';
diff --git a/services/platform/convex/predefined_workflows/customer_rag_sync.ts b/services/platform/convex/predefined_workflows/customer_rag_sync.ts
index 0ea6f85a82..2ed7705e28 100644
--- a/services/platform/convex/predefined_workflows/customer_rag_sync.ts
+++ b/services/platform/convex/predefined_workflows/customer_rag_sync.ts
@@ -88,12 +88,13 @@ export const customerRagSyncWorkflow = {
         type: 'rag',
         parameters: {
           operation: 'upload_text',
+          recordId:
+            '{{steps.find_unprocessed_customer.output.data.documents[0]._id}}',
           content:
             '{{steps.find_unprocessed_customer.output.data.documents[0]|string}}',
           metadata: {
             _id: '{{steps.find_unprocessed_customer.output.data.documents[0]._id}}',
           },
-          timeout: 600000, // 10 minutes for text upload
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/predefined_workflows/document_rag_sync.ts b/services/platform/convex/predefined_workflows/document_rag_sync.ts
index 68d0d4a523..86645a0217 100644
--- a/services/platform/convex/predefined_workflows/document_rag_sync.ts
+++ b/services/platform/convex/predefined_workflows/document_rag_sync.ts
@@ -87,14 +87,8 @@ export const documentRagSyncWorkflow = {
         type: 'rag',
         parameters: {
           operation: 'upload_document',
-          documentId:
+          recordId:
             '{{steps.find_unprocessed_document.output.data.documents[0]._id}}',
-          organizationId: '{{organizationId}}',
-          includeMetadata: '{{includeMetadata}}',
-          // With async RAG ingestion, this timeout only covers the HTTP request
-          // to enqueue ingestion plus Convex storage download + upload. Keep
-          // this comfortably below the overall workflow timeout.
-          timeout: 120000,
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/predefined_workflows/product_rag_sync.ts b/services/platform/convex/predefined_workflows/product_rag_sync.ts
index 3a9f63fc84..a5b262ef95 100644
--- a/services/platform/convex/predefined_workflows/product_rag_sync.ts
+++ b/services/platform/convex/predefined_workflows/product_rag_sync.ts
@@ -88,12 +88,13 @@ export const productRagSyncWorkflow = {
         type: 'rag',
         parameters: {
           operation: 'upload_text',
+          recordId:
+            '{{steps.find_unprocessed_product.output.data.documents[0]._id}}',
           content:
             '{{steps.find_unprocessed_product.output.data.documents[0]|string}}',
           metadata: {
             _id: '{{steps.find_unprocessed_product.output.data.documents[0]._id}}',
           },
-          timeout: 600000, // 10 minutes for text upload
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/predefined_workflows/website_pages_rag_sync.ts b/services/platform/convex/predefined_workflows/website_pages_rag_sync.ts
index 5432af479e..e36dfec568 100644
--- a/services/platform/convex/predefined_workflows/website_pages_rag_sync.ts
+++ b/services/platform/convex/predefined_workflows/website_pages_rag_sync.ts
@@ -78,6 +78,8 @@ export const websitePagesRagSyncWorkflow = {
         type: 'rag',
         parameters: {
           operation: 'upload_text',
+          recordId:
+            '{{steps.find_unprocessed_page.output.data.documents[0]._id}}',
           content:
             '{{steps.find_unprocessed_page.output.data.documents[0]|string}}',
           metadata: {
@@ -85,9 +87,6 @@ export const websitePagesRagSyncWorkflow = {
               '{{steps.find_unprocessed_page.output.data.documents[0].websiteId}}',
             _id: '{{steps.find_unprocessed_page.output.data.documents[0]._id}}',
           },
-          // Async ingestion means this timeout only covers the HTTP request to
-          // enqueue the page content, not full cognee processing.
-          timeout: 120000,
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/workflow/actions/approval/approval_action.ts b/services/platform/convex/workflow/actions/approval/approval_action.ts
index 1d707d2e55..7250c2a9df 100644
--- a/services/platform/convex/workflow/actions/approval/approval_action.ts
+++ b/services/platform/convex/workflow/actions/approval/approval_action.ts
@@ -12,13 +12,13 @@
 import { v } from 'convex/values';
 import type { ActionDefinition } from '../../helpers/nodes/action/types';
 import type { Id } from '../../../_generated/dataModel';
-import { createApproval } from './create_approval';
-import { updateApprovalStatus } from './update_approval_status';
-import { getApproval } from './get_approval';
-import { listPendingApprovals } from './list_pending_approvals';
-import { listApprovalsForExecution } from './list_approvals_for_execution';
-import { listPendingApprovalsForExecution } from './list_pending_approvals_for_execution';
-import { getApprovalHistory } from './get_approval_history';
+import { createApproval } from './helpers/create_approval';
+import { updateApprovalStatus } from './helpers/update_approval_status';
+import { getApproval } from './helpers/get_approval';
+import { listPendingApprovals } from './helpers/list_pending_approvals';
+import { listApprovalsForExecution } from './helpers/list_approvals_for_execution';
+import { listPendingApprovalsForExecution } from './helpers/list_pending_approvals_for_execution';
+import { getApprovalHistory } from './helpers/get_approval_history';
 
 export const approvalAction: ActionDefinition<{
   operation:
diff --git a/services/platform/convex/workflow/actions/approval/create_approval.ts b/services/platform/convex/workflow/actions/approval/helpers/create_approval.ts
similarity index 80%
rename from services/platform/convex/workflow/actions/approval/create_approval.ts
rename to services/platform/convex/workflow/actions/approval/helpers/create_approval.ts
index 24bffa9e50..b3c18ec381 100644
--- a/services/platform/convex/workflow/actions/approval/create_approval.ts
+++ b/services/platform/convex/workflow/actions/approval/helpers/create_approval.ts
@@ -1,8 +1,8 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { CreateApprovalResult, ApprovalPriority } from './types';
-import type { ApprovalResourceType } from '../../../model/approvals/types';
+import type { ApprovalResourceType } from '../../../../model/approvals/types';
 
 export async function createApproval(
   ctx: ActionCtx,
diff --git a/services/platform/convex/workflow/actions/approval/get_approval.ts b/services/platform/convex/workflow/actions/approval/helpers/get_approval.ts
similarity index 67%
rename from services/platform/convex/workflow/actions/approval/get_approval.ts
rename to services/platform/convex/workflow/actions/approval/helpers/get_approval.ts
index 280226d2d1..f72d7e9884 100644
--- a/services/platform/convex/workflow/actions/approval/get_approval.ts
+++ b/services/platform/convex/workflow/actions/approval/helpers/get_approval.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { GetApprovalResult } from './types';
 
 export async function getApproval(
diff --git a/services/platform/convex/workflow/actions/approval/get_approval_history.ts b/services/platform/convex/workflow/actions/approval/helpers/get_approval_history.ts
similarity index 81%
rename from services/platform/convex/workflow/actions/approval/get_approval_history.ts
rename to services/platform/convex/workflow/actions/approval/helpers/get_approval_history.ts
index 504b800148..d5bdeeea98 100644
--- a/services/platform/convex/workflow/actions/approval/get_approval_history.ts
+++ b/services/platform/convex/workflow/actions/approval/helpers/get_approval_history.ts
@@ -1,7 +1,7 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
 import type { ListApprovalsResult } from './types';
-import type { ApprovalResourceType } from '../../../model/approvals/types';
+import type { ApprovalResourceType } from '../../../../model/approvals/types';
 
 const VALID_RESOURCE_TYPES: ApprovalResourceType[] = [
   'conversations',
diff --git a/services/platform/convex/workflow/actions/approval/list_approvals_for_execution.ts b/services/platform/convex/workflow/actions/approval/helpers/list_approvals_for_execution.ts
similarity index 72%
rename from services/platform/convex/workflow/actions/approval/list_approvals_for_execution.ts
rename to services/platform/convex/workflow/actions/approval/helpers/list_approvals_for_execution.ts
index 8ffad6fde3..dc26c16803 100644
--- a/services/platform/convex/workflow/actions/approval/list_approvals_for_execution.ts
+++ b/services/platform/convex/workflow/actions/approval/helpers/list_approvals_for_execution.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { ListApprovalsResult } from './types';
 
 export async function listApprovalsForExecution(
@@ -22,4 +22,3 @@ export async function listApprovalsForExecution(
     count: approvals.length,
   };
 }
-
diff --git a/services/platform/convex/workflow/actions/approval/list_pending_approvals.ts b/services/platform/convex/workflow/actions/approval/helpers/list_pending_approvals.ts
similarity index 83%
rename from services/platform/convex/workflow/actions/approval/list_pending_approvals.ts
rename to services/platform/convex/workflow/actions/approval/helpers/list_pending_approvals.ts
index 051a0be3b1..2015984f6a 100644
--- a/services/platform/convex/workflow/actions/approval/list_pending_approvals.ts
+++ b/services/platform/convex/workflow/actions/approval/helpers/list_pending_approvals.ts
@@ -1,7 +1,7 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
 import type { ListApprovalsResult } from './types';
-import type { ApprovalResourceType } from '../../../model/approvals/types';
+import type { ApprovalResourceType } from '../../../../model/approvals/types';
 
 const VALID_RESOURCE_TYPES: ApprovalResourceType[] = [
   'conversations',
diff --git a/services/platform/convex/workflow/actions/approval/list_pending_approvals_for_execution.ts b/services/platform/convex/workflow/actions/approval/helpers/list_pending_approvals_for_execution.ts
similarity index 73%
rename from services/platform/convex/workflow/actions/approval/list_pending_approvals_for_execution.ts
rename to services/platform/convex/workflow/actions/approval/helpers/list_pending_approvals_for_execution.ts
index 8c800341e9..3eeea9f155 100644
--- a/services/platform/convex/workflow/actions/approval/list_pending_approvals_for_execution.ts
+++ b/services/platform/convex/workflow/actions/approval/helpers/list_pending_approvals_for_execution.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { ListApprovalsResult } from './types';
 
 export async function listPendingApprovalsForExecution(
@@ -22,4 +22,3 @@ export async function listPendingApprovalsForExecution(
     count: approvals.length,
   };
 }
-
diff --git a/services/platform/convex/workflow/actions/approval/types.ts b/services/platform/convex/workflow/actions/approval/helpers/types.ts
similarity index 91%
rename from services/platform/convex/workflow/actions/approval/types.ts
rename to services/platform/convex/workflow/actions/approval/helpers/types.ts
index b6137c3288..d00df67255 100644
--- a/services/platform/convex/workflow/actions/approval/types.ts
+++ b/services/platform/convex/workflow/actions/approval/helpers/types.ts
@@ -1,5 +1,5 @@
-import type { Id } from '../../../_generated/dataModel';
-import type { ApprovalResourceType } from '../../../model/approvals/types';
+import type { Id } from '../../../../_generated/dataModel';
+import type { ApprovalResourceType } from '../../../../model/approvals/types';
 
 export type ApprovalStatus = 'pending' | 'approved' | 'rejected';
 export type ApprovalPriority = 'low' | 'medium' | 'high' | 'urgent';
diff --git a/services/platform/convex/workflow/actions/approval/update_approval_status.ts b/services/platform/convex/workflow/actions/approval/helpers/update_approval_status.ts
similarity index 78%
rename from services/platform/convex/workflow/actions/approval/update_approval_status.ts
rename to services/platform/convex/workflow/actions/approval/helpers/update_approval_status.ts
index 6086ce4591..f14ad56f02 100644
--- a/services/platform/convex/workflow/actions/approval/update_approval_status.ts
+++ b/services/platform/convex/workflow/actions/approval/helpers/update_approval_status.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { UpdateApprovalStatusResult, ApprovalStatus } from './types';
 
 export async function updateApprovalStatus(
diff --git a/services/platform/convex/workflow/actions/conversation/conversation_action.ts b/services/platform/convex/workflow/actions/conversation/conversation_action.ts
index 8a11525fd0..1362baf27e 100644
--- a/services/platform/convex/workflow/actions/conversation/conversation_action.ts
+++ b/services/platform/convex/workflow/actions/conversation/conversation_action.ts
@@ -13,15 +13,15 @@
 import { v } from 'convex/values';
 import type { ActionDefinition } from '../../helpers/nodes/action/types';
 import type { Id } from '../../../_generated/dataModel';
-import { createConversation } from './create_conversation';
-import { getConversationById } from './get_conversation_by_id';
-import { queryConversations } from './query_conversations';
-import { queryConversationMessages } from './query_conversation_messages';
-import { queryLatestMessageByDeliveryState } from './query_latest_message_by_delivery_state';
-import { updateConversations } from './update_conversations';
-import { createConversationFromEmail } from './create_conversation_from_email';
-import { createConversationFromSentEmail } from './create_conversation_from_sent_email';
-import type { ConversationStatus } from './types';
+import { createConversation } from './helpers/create_conversation';
+import { getConversationById } from './helpers/get_conversation_by_id';
+import { queryConversations } from './helpers/query_conversations';
+import { queryConversationMessages } from './helpers/query_conversation_messages';
+import { queryLatestMessageByDeliveryState } from './helpers/query_latest_message_by_delivery_state';
+import { updateConversations } from './helpers/update_conversations';
+import { createConversationFromEmail } from './helpers/create_conversation_from_email';
+import { createConversationFromSentEmail } from './helpers/create_conversation_from_sent_email';
+import type { ConversationStatus } from './helpers/types';
 
 export const conversationAction: ActionDefinition<{
   operation:
diff --git a/services/platform/convex/workflow/actions/conversation/helpers/add_message_to_conversation.ts b/services/platform/convex/workflow/actions/conversation/helpers/add_message_to_conversation.ts
index ec8ab1f13e..4204d1fb02 100644
--- a/services/platform/convex/workflow/actions/conversation/helpers/add_message_to_conversation.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/add_message_to_conversation.ts
@@ -1,7 +1,7 @@
 import type { ActionCtx } from '../../../../_generated/server';
 import { internal } from '../../../../_generated/api';
 import type { Id } from '../../../../_generated/dataModel';
-import type { EmailType } from '../types';
+import type { EmailType } from './types';
 import { buildEmailMetadata } from './build_email_metadata';
 
 /**
diff --git a/services/platform/convex/workflow/actions/conversation/helpers/build_conversation_metadata.ts b/services/platform/convex/workflow/actions/conversation/helpers/build_conversation_metadata.ts
index 0f7ab2135b..af14e453be 100644
--- a/services/platform/convex/workflow/actions/conversation/helpers/build_conversation_metadata.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/build_conversation_metadata.ts
@@ -1,4 +1,4 @@
-import type { EmailType } from '../types';
+import type { EmailType } from './types';
 
 /**
  * Build conversation metadata object
diff --git a/services/platform/convex/workflow/actions/conversation/helpers/build_email_metadata.ts b/services/platform/convex/workflow/actions/conversation/helpers/build_email_metadata.ts
index deeaa19a09..8281504320 100644
--- a/services/platform/convex/workflow/actions/conversation/helpers/build_email_metadata.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/build_email_metadata.ts
@@ -1,4 +1,4 @@
-import type { EmailType } from '../types';
+import type { EmailType } from './types';
 
 /**
  * Build rich metadata object for email message
diff --git a/services/platform/convex/workflow/actions/conversation/helpers/build_initial_message.ts b/services/platform/convex/workflow/actions/conversation/helpers/build_initial_message.ts
index 56b1ab5571..6c81fe10e7 100644
--- a/services/platform/convex/workflow/actions/conversation/helpers/build_initial_message.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/build_initial_message.ts
@@ -1,4 +1,4 @@
-import type { EmailType } from '../types';
+import type { EmailType } from './types';
 import { buildEmailMetadata } from './build_email_metadata';
 
 /**
diff --git a/services/platform/convex/workflow/actions/conversation/create_conversation.ts b/services/platform/convex/workflow/actions/conversation/helpers/create_conversation.ts
similarity index 85%
rename from services/platform/convex/workflow/actions/conversation/create_conversation.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/create_conversation.ts
index ec1818a620..b2fe18304e 100644
--- a/services/platform/convex/workflow/actions/conversation/create_conversation.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/create_conversation.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { ConversationStatus } from './types';
 
 export async function createConversation(
@@ -39,3 +39,4 @@ export async function createConversation(
     timestamp: Date.now(),
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/conversation/create_conversation_from_email.ts b/services/platform/convex/workflow/actions/conversation/helpers/create_conversation_from_email.ts
similarity index 91%
rename from services/platform/convex/workflow/actions/conversation/create_conversation_from_email.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/create_conversation_from_email.ts
index 22623bcd80..e1096c6908 100644
--- a/services/platform/convex/workflow/actions/conversation/create_conversation_from_email.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/create_conversation_from_email.ts
@@ -1,16 +1,16 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { EmailType, ConversationStatus } from './types';
-import { checkMessageExists } from './helpers/check_message_exists';
-import { checkConversationExists } from './helpers/check_conversation_exists';
-import { findOrCreateCustomerFromEmail } from './helpers/find_or_create_customer_from_email';
-import { addMessageToConversation } from './helpers/add_message_to_conversation';
-import { updateMessage } from './helpers/update_message';
-import { buildInitialMessage } from './helpers/build_initial_message';
-import { buildConversationMetadata } from './helpers/build_conversation_metadata';
-
-import { createDebugLog } from '../../../lib/debug_log';
+import { checkMessageExists } from './check_message_exists';
+import { checkConversationExists } from './check_conversation_exists';
+import { findOrCreateCustomerFromEmail } from './find_or_create_customer_from_email';
+import { addMessageToConversation } from './add_message_to_conversation';
+import { updateMessage } from './update_message';
+import { buildInitialMessage } from './build_initial_message';
+import { buildConversationMetadata } from './build_conversation_metadata';
+
+import { createDebugLog } from '../../../../lib/debug_log';
 
 const debugLog = createDebugLog('DEBUG_CONVERSATIONS', '[Conversations]');
 
diff --git a/services/platform/convex/workflow/actions/conversation/create_conversation_from_sent_email.ts b/services/platform/convex/workflow/actions/conversation/helpers/create_conversation_from_sent_email.ts
similarity index 87%
rename from services/platform/convex/workflow/actions/conversation/create_conversation_from_sent_email.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/create_conversation_from_sent_email.ts
index d76206590a..74e8954128 100644
--- a/services/platform/convex/workflow/actions/conversation/create_conversation_from_sent_email.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/create_conversation_from_sent_email.ts
@@ -1,16 +1,16 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { EmailType, ConversationStatus } from './types';
-import { checkMessageExists } from './helpers/check_message_exists';
-import { findOrCreateCustomerFromEmail } from './helpers/find_or_create_customer_from_email';
-import { findRelatedConversation } from './helpers/find_related_conversation';
-import { addMessageToConversation } from './helpers/add_message_to_conversation';
-import { updateMessage } from './helpers/update_message';
-import { buildInitialMessage } from './helpers/build_initial_message';
-import { buildConversationMetadata } from './helpers/build_conversation_metadata';
+import { checkMessageExists } from './check_message_exists';
+import { findOrCreateCustomerFromEmail } from './find_or_create_customer_from_email';
+import { findRelatedConversation } from './find_related_conversation';
+import { addMessageToConversation } from './add_message_to_conversation';
+import { updateMessage } from './update_message';
+import { buildInitialMessage } from './build_initial_message';
+import { buildConversationMetadata } from './build_conversation_metadata';
 
-import { createDebugLog } from '../../../lib/debug_log';
+import { createDebugLog } from '../../../../lib/debug_log';
 
 const debugLog = createDebugLog('DEBUG_CONVERSATIONS', '[Conversations]');
 
@@ -47,6 +47,26 @@ export async function createConversationFromSentEmail(
     rootEmail.messageId,
   );
 
+  // Helper: does an address list include a given email?
+  const listIncludes = (
+    list: Array<{ address: string; name?: string }> | undefined,
+    addr: string | undefined,
+  ) =>
+    !!addr &&
+    !!list?.some((x) => x.address?.toLowerCase() === addr.toLowerCase());
+
+  // Collect all unique addresses from the thread
+  const allAddresses = new Set<string>();
+  for (const email of emailsArray) {
+    if (email.from?.[0]?.address)
+      allAddresses.add(email.from[0].address.toLowerCase());
+    if (email.to?.[0]?.address)
+      allAddresses.add(email.to[0].address.toLowerCase());
+  }
+
+  // Prefer explicit accountEmail if provided (most reliable)
+  const explicitAgent = params.accountEmail?.toLowerCase();
+
   if (existing) {
     debugLog(
       'create_from_sent_email Root conversation already exists:',
@@ -77,24 +97,6 @@ export async function createConversationFromSentEmail(
         continue;
       }
 
-      // Determine customer email (reuse logic from below)
-      const explicitAgent = params.accountEmail?.toLowerCase();
-      const listIncludes = (
-        list: Array<{ address: string; name?: string }> | undefined,
-        addr: string | undefined,
-      ) =>
-        !!addr &&
-        !!list?.some((x) => x.address?.toLowerCase() === addr.toLowerCase());
-
-      // Collect all unique addresses from the thread
-      const allAddresses = new Set<string>();
-      for (const threadEmail of emailsArray) {
-        if (threadEmail.from?.[0]?.address)
-          allAddresses.add(threadEmail.from[0].address.toLowerCase());
-        if (threadEmail.to?.[0]?.address)
-          allAddresses.add(threadEmail.to[0].address.toLowerCase());
-      }
-
       // Determine customer email
       let customerEmail: string | undefined;
       let accountEmailLower = explicitAgent;
@@ -164,27 +166,6 @@ export async function createConversationFromSentEmail(
     };
   }
 
-  // Determine the customer email from the thread
-  // Prefer explicit accountEmail if provided (most reliable)
-  const explicitAgent = params.accountEmail?.toLowerCase();
-
-  // Helper: does an address list include a given email?
-  const listIncludes = (
-    list: Array<{ address: string; name?: string }> | undefined,
-    addr: string | undefined,
-  ) =>
-    !!addr &&
-    !!list?.some((x) => x.address?.toLowerCase() === addr.toLowerCase());
-
-  // Collect all unique addresses from the thread
-  const allAddresses = new Set<string>();
-  for (const email of emailsArray) {
-    if (email.from?.[0]?.address)
-      allAddresses.add(email.from[0].address.toLowerCase());
-    if (email.to?.[0]?.address)
-      allAddresses.add(email.to[0].address.toLowerCase());
-  }
-
   // Determine agent and customer
   let accountEmailLower = explicitAgent;
   let customerEmail: string | undefined;
diff --git a/services/platform/convex/workflow/actions/conversation/helpers/find_or_create_customer_from_email.ts b/services/platform/convex/workflow/actions/conversation/helpers/find_or_create_customer_from_email.ts
index 4df1cd22b3..45400c7ecb 100644
--- a/services/platform/convex/workflow/actions/conversation/helpers/find_or_create_customer_from_email.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/find_or_create_customer_from_email.ts
@@ -1,7 +1,7 @@
 import type { ActionCtx } from '../../../../_generated/server';
 import { internal } from '../../../../_generated/api';
 import type { Id } from '../../../../_generated/dataModel';
-import type { EmailType } from '../types';
+import type { EmailType } from './types';
 
 /**
  * Find or create customer based on email direction
diff --git a/services/platform/convex/workflow/actions/conversation/helpers/find_related_conversation.ts b/services/platform/convex/workflow/actions/conversation/helpers/find_related_conversation.ts
index b0a09ef1a7..abdcdda6da 100644
--- a/services/platform/convex/workflow/actions/conversation/helpers/find_related_conversation.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/find_related_conversation.ts
@@ -1,6 +1,6 @@
 import type { ActionCtx } from '../../../../_generated/server';
 import type { Id } from '../../../../_generated/dataModel';
-import type { EmailType } from '../types';
+import type { EmailType } from './types';
 import { checkMessageExists } from './check_message_exists';
 
 /**
diff --git a/services/platform/convex/workflow/actions/conversation/get_conversation_by_id.ts b/services/platform/convex/workflow/actions/conversation/helpers/get_conversation_by_id.ts
similarity index 69%
rename from services/platform/convex/workflow/actions/conversation/get_conversation_by_id.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/get_conversation_by_id.ts
index 10c0bb535c..f4af96c8a5 100644
--- a/services/platform/convex/workflow/actions/conversation/get_conversation_by_id.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/get_conversation_by_id.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 
 export async function getConversationById(
   ctx: ActionCtx,
diff --git a/services/platform/convex/workflow/actions/conversation/query_conversation_messages.ts b/services/platform/convex/workflow/actions/conversation/helpers/query_conversation_messages.ts
similarity index 82%
rename from services/platform/convex/workflow/actions/conversation/query_conversation_messages.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/query_conversation_messages.ts
index cb49e765cc..9f7d2861ee 100644
--- a/services/platform/convex/workflow/actions/conversation/query_conversation_messages.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/query_conversation_messages.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { QueryResult } from './types';
 
 export async function queryConversationMessages(
@@ -36,3 +36,4 @@ export async function queryConversationMessages(
     timestamp: Date.now(),
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/conversation/query_conversations.ts b/services/platform/convex/workflow/actions/conversation/helpers/query_conversations.ts
similarity index 84%
rename from services/platform/convex/workflow/actions/conversation/query_conversations.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/query_conversations.ts
index 0663890eaa..f91d616b3d 100644
--- a/services/platform/convex/workflow/actions/conversation/query_conversations.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/query_conversations.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { QueryResult, ConversationStatus } from './types';
 
 export async function queryConversations(
@@ -40,3 +40,4 @@ export async function queryConversations(
     timestamp: Date.now(),
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/conversation/query_latest_message_by_delivery_state.ts b/services/platform/convex/workflow/actions/conversation/helpers/query_latest_message_by_delivery_state.ts
similarity index 80%
rename from services/platform/convex/workflow/actions/conversation/query_latest_message_by_delivery_state.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/query_latest_message_by_delivery_state.ts
index 1edd432119..8777bdfdf1 100644
--- a/services/platform/convex/workflow/actions/conversation/query_latest_message_by_delivery_state.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/query_latest_message_by_delivery_state.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import type { Id } from '../../../_generated/dataModel';
-import { internal } from '../../../_generated/api';
+import type { ActionCtx } from '../../../../_generated/server';
+import type { Id } from '../../../../_generated/dataModel';
+import { internal } from '../../../../_generated/api';
 
 export async function queryLatestMessageByDeliveryState(
   ctx: ActionCtx,
@@ -29,3 +29,4 @@ export async function queryLatestMessageByDeliveryState(
     timestamp: Date.now(),
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/conversation/types.ts b/services/platform/convex/workflow/actions/conversation/helpers/types.ts
similarity index 93%
rename from services/platform/convex/workflow/actions/conversation/types.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/types.ts
index c1a333e0a6..f97914d818 100644
--- a/services/platform/convex/workflow/actions/conversation/types.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/types.ts
@@ -1,4 +1,4 @@
-import type { Id } from '../../../_generated/dataModel';
+import type { Id } from '../../../../_generated/dataModel';
 
 export type UpdateConversationsResult = {
   success: boolean;
diff --git a/services/platform/convex/workflow/actions/conversation/update_conversations.ts b/services/platform/convex/workflow/actions/conversation/helpers/update_conversations.ts
similarity index 82%
rename from services/platform/convex/workflow/actions/conversation/update_conversations.ts
rename to services/platform/convex/workflow/actions/conversation/helpers/update_conversations.ts
index d7d54a6530..5e7a9df0ec 100644
--- a/services/platform/convex/workflow/actions/conversation/update_conversations.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/update_conversations.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { UpdateConversationsResult, ConversationStatus } from './types';
 
 export async function updateConversations(
@@ -32,3 +32,4 @@ export async function updateConversations(
     timestamp: Date.now(),
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/conversation/helpers/update_message.ts b/services/platform/convex/workflow/actions/conversation/helpers/update_message.ts
index 4400bf46f8..5577be44ec 100644
--- a/services/platform/convex/workflow/actions/conversation/helpers/update_message.ts
+++ b/services/platform/convex/workflow/actions/conversation/helpers/update_message.ts
@@ -1,7 +1,7 @@
 import type { ActionCtx } from '../../../../_generated/server';
 import { internal } from '../../../../_generated/api';
 import type { Id } from '../../../../_generated/dataModel';
-import type { EmailType } from '../types';
+import type { EmailType } from './types';
 import { buildEmailMetadata } from './build_email_metadata';
 
 /**
diff --git a/services/platform/convex/workflow/actions/crawler/crawler_action.ts b/services/platform/convex/workflow/actions/crawler/crawler_action.ts
index f7435fae81..11d7badd06 100644
--- a/services/platform/convex/workflow/actions/crawler/crawler_action.ts
+++ b/services/platform/convex/workflow/actions/crawler/crawler_action.ts
@@ -5,7 +5,7 @@ import type {
   CrawlerResult,
   DiscoverUrlsResult,
   FetchUrlsResult,
-} from './types';
+} from './helpers/types';
 
 import { createDebugLog } from '../../../lib/debug_log';
 
diff --git a/services/platform/convex/workflow/actions/crawler/types.ts b/services/platform/convex/workflow/actions/crawler/helpers/types.ts
similarity index 99%
rename from services/platform/convex/workflow/actions/crawler/types.ts
rename to services/platform/convex/workflow/actions/crawler/helpers/types.ts
index 906cd4e064..4077c683ab 100644
--- a/services/platform/convex/workflow/actions/crawler/types.ts
+++ b/services/platform/convex/workflow/actions/crawler/helpers/types.ts
@@ -53,3 +53,4 @@ export interface FetchUrlsResult {
     structured_data?: Record<string, unknown>;
   }>;
 }
+
diff --git a/services/platform/convex/workflow/actions/imap/README.md b/services/platform/convex/workflow/actions/imap/README.md
deleted file mode 100644
index 75b085232b..0000000000
--- a/services/platform/convex/workflow/actions/imap/README.md
+++ /dev/null
@@ -1,309 +0,0 @@
-# IMAP Email Retrieval Action
-
-This action allows you to retrieve emails from any IMAP-compatible email server (Gmail, Outlook, Yahoo, etc.) within your workflows.
-
-## Features
-
-- **Multiple Operations**: List, search, or get specific emails
-- **Flexible Authentication**: Support for standard IMAP credentials
-- **Advanced Search**: Filter emails by sender, recipient, subject, date, flags, etc.
-- **Attachment Support**: Optionally include attachment metadata
-- **HTML Parsing**: Optionally parse HTML content
-- **Mark as Read**: Optionally mark retrieved emails as seen
-- **Pagination**: Support for offset and limit to handle large mailboxes
-
-## Configuration
-
-### Credentials
-
-You can provide IMAP credentials in two ways:
-
-1. **In action parameters** (for testing or single-use):
-
-```typescript
-{
-  type: 'imap',
-  config: {
-    parameters: {
-      host: 'imap.gmail.com',
-      port: 993,
-      secure: true,
-      username: 'user@gmail.com',
-      password: 'app-password',
-      operation: 'list',
-    },
-  },
-}
-```
-
-2. **In workflow variables** (recommended for reusable workflows):
-
-```typescript
-{
-  workflowConfig: {
-    config: {
-      variables: {
-        imapHost: 'imap.gmail.com',
-        imapPort: 993,
-        imapSecure: true,
-        imapUsername: 'user@gmail.com',
-        imapPassword: 'app-password',
-      },
-    },
-  },
-}
-```
-
-### Common IMAP Servers
-
-| Provider           | Host                  | Port | Secure |
-| ------------------ | --------------------- | ---- | ------ |
-| Gmail              | imap.gmail.com        | 993  | true   |
-| Outlook/Office 365 | outlook.office365.com | 993  | true   |
-| Yahoo              | imap.mail.yahoo.com   | 993  | true   |
-| iCloud             | imap.mail.me.com      | 993  | true   |
-
-**Note for Gmail**: You need to use an [App Password](https://support.google.com/accounts/answer/185833) instead of your regular password.
-
-## Operations
-
-### 1. List Emails
-
-Retrieve the most recent emails from a mailbox:
-
-```typescript
-{
-  type: 'imap',
-  config: {
-    parameters: {
-      operation: 'list',
-      mailbox: 'INBOX', // Optional, defaults to 'INBOX'
-      limit: 50, // Optional, defaults to 50
-      offset: 0, // Optional, defaults to 0
-      markAsSeen: false, // Optional, defaults to false
-      includeAttachments: true, // Optional, defaults to false
-      parseHtml: true, // Optional, defaults to false
-    },
-  },
-}
-```
-
-### 2. Search Emails
-
-Search for emails matching specific criteria:
-
-```typescript
-{
-  type: 'imap',
-  config: {
-    parameters: {
-      operation: 'search',
-      searchCriteria: {
-        from: 'sender@example.com', // Optional
-        to: 'recipient@example.com', // Optional
-        subject: 'Invoice', // Optional
-        since: '2024-01-01', // Optional, ISO date string
-        before: '2024-12-31', // Optional, ISO date string
-        unseen: true, // Optional, only unread emails
-        flagged: false, // Optional
-      },
-      limit: 100,
-      markAsSeen: false,
-      includeAttachments: true,
-    },
-  },
-}
-```
-
-### 3. Get Specific Email
-
-Retrieve a specific email by UID:
-
-```typescript
-{
-  type: 'imap',
-  config: {
-    parameters: {
-      operation: 'get',
-      uid: 12345, // Required for 'get' operation
-      markAsSeen: true,
-      includeAttachments: true,
-      parseHtml: true,
-    },
-  },
-}
-```
-
-## Response Format
-
-The action returns an object with the following structure:
-
-```typescript
-{
-  success: true,
-  operation: 'list' | 'search' | 'get',
-  mailbox: 'INBOX',
-  messages: [
-    {
-      uid: 12345,
-      messageId: '<unique-message-id@example.com>',
-      from: [{ name: 'John Doe', address: 'john@example.com' }],
-      to: [{ name: 'Jane Smith', address: 'jane@example.com' }],
-      cc: [{ name: 'Bob', address: 'bob@example.com' }], // Optional
-      bcc: [], // Optional
-      subject: 'Important Email',
-      date: '2024-01-15T10:30:00.000Z',
-      text: 'Plain text content...',
-      html: '<html>...</html>', // Only if parseHtml: true
-      attachments: [ // Only if includeAttachments: true
-        {
-          filename: 'document.pdf',
-          contentType: 'application/pdf',
-          size: 102400,
-        },
-      ],
-      flags: ['\\Seen', '\\Flagged'],
-      headers: { // Optional
-        'x-custom-header': 'value',
-      },
-    },
-  ],
-  count: 1,
-  duration: 1234, // milliseconds
-  timestamp: 1705315800000,
-}
-```
-
-## Example Workflows
-
-### Example 1: Process Unread Emails
-
-```typescript
-{
-  workflowConfig: {
-    name: 'Process Unread Emails',
-    workflowType: 'predefined',
-    config: {
-      variables: {
-        imapHost: 'imap.gmail.com',
-        imapPort: 993,
-        imapSecure: true,
-        imapUsername: 'support@company.com',
-        imapPassword: '${secrets.GMAIL_APP_PASSWORD}',
-      },
-    },
-  },
-  steps: [
-    {
-      id: 'trigger',
-      type: 'trigger',
-      config: { type: 'manual' },
-    },
-    {
-      id: 'fetch_unread',
-      type: 'action',
-      config: {
-        type: 'imap',
-        parameters: {
-          operation: 'search',
-          searchCriteria: {
-            unseen: true,
-          },
-          limit: 20,
-          markAsSeen: true,
-          includeAttachments: true,
-        },
-      },
-    },
-    {
-      id: 'process_emails',
-      type: 'loop',
-      config: {
-        items: '${fetch_unread.messages}',
-        itemVariable: 'email',
-      },
-    },
-    // ... process each email
-  ],
-}
-```
-
-### Example 2: Search for Invoices
-
-```typescript
-{
-  id: 'search_invoices',
-  type: 'action',
-  config: {
-    type: 'imap',
-    parameters: {
-      operation: 'search',
-      searchCriteria: {
-        from: 'billing@vendor.com',
-        subject: 'Invoice',
-        since: '2024-01-01',
-        unseen: true,
-      },
-      limit: 50,
-      includeAttachments: true,
-    },
-  },
-}
-```
-
-## Error Handling
-
-The action will throw an error if:
-
-- IMAP credentials are missing or invalid
-- Connection to the IMAP server fails
-- The specified mailbox doesn't exist
-- Required parameters are missing (e.g., `uid` for 'get' operation)
-- Search criteria are missing for 'search' operation
-
-## Security Best Practices
-
-1. **Use App Passwords**: For Gmail and other providers, use app-specific passwords instead of your main account password
-2. **Store Credentials Securely**: Use workflow secrets for passwords: `${secrets.IMAP_PASSWORD}`
-3. **Limit Access**: Use dedicated email accounts for automation with minimal permissions
-4. **Enable 2FA**: Enable two-factor authentication on your email account
-5. **Monitor Usage**: Regularly review which workflows have access to email credentials
-
-## Performance Considerations
-
-- **Limit Results**: Use the `limit` parameter to avoid retrieving too many emails at once
-- **Use Search**: Use the `search` operation with specific criteria instead of listing all emails
-- **Pagination**: Use `offset` and `limit` for pagination when processing large mailboxes
-- **Mark as Seen**: Consider using `markAsSeen: true` to avoid processing the same emails multiple times
-- **Timeout**: Adjust the `timeout` parameter if you're experiencing connection issues (default: 30000ms)
-
-## Troubleshooting
-
-### Connection Timeout
-
-- Increase the `timeout` parameter
-- Check your network connectivity
-- Verify the IMAP server address and port
-
-### Authentication Failed
-
-- Verify your username and password
-- For Gmail, ensure you're using an App Password
-- Check if IMAP is enabled in your email account settings
-
-### No Emails Returned
-
-- Verify the mailbox name (case-sensitive)
-- Check your search criteria
-- Ensure there are emails matching your criteria
-
-## File Structure
-
-```
-imap/
-├── imap_action.ts              # Main action definition
-├── types.ts                    # TypeScript interfaces
-├── get_imap_credentials.ts     # Credential helper
-├── retrieve_imap_emails.ts     # IMAP client implementation
-└── README.md                   # This file
-```
diff --git a/services/platform/convex/workflow/actions/imap/get_imap_credentials.ts b/services/platform/convex/workflow/actions/imap/helpers/get_imap_credentials.ts
similarity index 99%
rename from services/platform/convex/workflow/actions/imap/get_imap_credentials.ts
rename to services/platform/convex/workflow/actions/imap/helpers/get_imap_credentials.ts
index 7e78906bf4..0ed40350af 100644
--- a/services/platform/convex/workflow/actions/imap/get_imap_credentials.ts
+++ b/services/platform/convex/workflow/actions/imap/helpers/get_imap_credentials.ts
@@ -69,3 +69,4 @@ export function getImapCredentials(
     accessToken,
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/imap/types.ts b/services/platform/convex/workflow/actions/imap/helpers/types.ts
similarity index 99%
rename from services/platform/convex/workflow/actions/imap/types.ts
rename to services/platform/convex/workflow/actions/imap/helpers/types.ts
index 845567651b..907e65e795 100644
--- a/services/platform/convex/workflow/actions/imap/types.ts
+++ b/services/platform/convex/workflow/actions/imap/helpers/types.ts
@@ -58,3 +58,4 @@ export interface ImapActionResult {
   duration: number;
   timestamp: number;
 }
+
diff --git a/services/platform/convex/workflow/actions/imap/imap_action.ts b/services/platform/convex/workflow/actions/imap/imap_action.ts
index c4388f4087..f3221ed8a8 100644
--- a/services/platform/convex/workflow/actions/imap/imap_action.ts
+++ b/services/platform/convex/workflow/actions/imap/imap_action.ts
@@ -1,7 +1,7 @@
 import { v } from 'convex/values';
 import type { ActionDefinition } from '../../helpers/nodes/action/types';
-import type { ImapActionParams, ImapActionResult } from './types';
-import { getImapCredentials } from './get_imap_credentials';
+import type { ImapActionParams, ImapActionResult } from './helpers/types';
+import { getImapCredentials } from './helpers/get_imap_credentials';
 import { internal } from '../../../_generated/api';
 
 export const imapAction: ActionDefinition<ImapActionParams> = {
diff --git a/services/platform/convex/workflow/actions/integration/build_secrets_from_integration.ts b/services/platform/convex/workflow/actions/integration/helpers/build_secrets_from_integration.ts
similarity index 86%
rename from services/platform/convex/workflow/actions/integration/build_secrets_from_integration.ts
rename to services/platform/convex/workflow/actions/integration/helpers/build_secrets_from_integration.ts
index fe00d18765..a2c5d6519e 100644
--- a/services/platform/convex/workflow/actions/integration/build_secrets_from_integration.ts
+++ b/services/platform/convex/workflow/actions/integration/helpers/build_secrets_from_integration.ts
@@ -3,9 +3,9 @@
  * Maps secretBindings to actual decrypted values
  */
 
-import type { Doc } from '../../../_generated/dataModel';
-import type { ActionDefinition } from '../../helpers/nodes/action/types';
-import { internal } from '../../../_generated/api';
+import type { Doc } from '../../../../_generated/dataModel';
+import type { ActionDefinition } from '../../../helpers/nodes/action/types';
+import { internal } from '../../../../_generated/api';
 
 export async function buildSecretsFromIntegration(
   ctx: Parameters<ActionDefinition<unknown>['execute']>[0],
diff --git a/services/platform/convex/workflow/actions/integration/integration_action.ts b/services/platform/convex/workflow/actions/integration/integration_action.ts
index e294a83573..00e70db66d 100644
--- a/services/platform/convex/workflow/actions/integration/integration_action.ts
+++ b/services/platform/convex/workflow/actions/integration/integration_action.ts
@@ -15,7 +15,7 @@ import { internal } from '../../../_generated/api';
 import type { Doc } from '../../../_generated/dataModel';
 import type { IntegrationExecutionResult } from '../../../node_only/integration_sandbox/types';
 import { getPredefinedIntegration } from '../../../predefined_integrations';
-import { buildSecretsFromIntegration } from './build_secrets_from_integration';
+import { buildSecretsFromIntegration } from './helpers/build_secrets_from_integration';
 
 import { createDebugLog } from '../../../lib/debug_log';
 
diff --git a/services/platform/convex/workflow/actions/product/README.md b/services/platform/convex/workflow/actions/product/README.md
deleted file mode 100644
index 91d94927ef..0000000000
--- a/services/platform/convex/workflow/actions/product/README.md
+++ /dev/null
@@ -1,258 +0,0 @@
-# Product Action
-
-Product-specific workflow actions for safe, specialized operations on product data.
-
-## Operations
-
-### 1. create
-Create a new product.
-
-**Required Parameters:**
-- `organizationId`: Organization ID
-- `name`: Product name
-
-**Optional Parameters:**
-- `description`: Product description
-- `imageUrl`: Product image URL
-- `stock`: Stock quantity
-- `price`: Product price
-- `currency`: Currency code
-- `category`: Product category
-- `tags`: Array of tags
-- `status`: Product status (active, inactive, draft, archived)
-- `externalId`: External system ID
-- `metadata`: Additional metadata
-
-**Example:**
-```typescript
-{
-  operation: 'create',
-  organizationId: 'org_123',
-  name: 'Premium Laptop',
-  price: 1299,
-  status: 'active'
-}
-```
-
-### 2. get_by_id
-Get a product by its ID.
-
-**Required Parameters:**
-- `productId`: Product ID
-
-**Example:**
-```typescript
-{
-  operation: 'get_by_id',
-  productId: 'prod_123'
-}
-```
-
-### 3. query
-Query products with pagination and filtering.
-
-**Required Parameters:**
-- `organizationId`: Organization ID
-- `paginationOpts`: Pagination options
-  - `numItems`: Number of items per page
-  - `cursor`: Pagination cursor (null for first page)
-
-**Optional Parameters:**
-- `externalId`: Filter by external ID
-- `status`: Filter by status
-- `category`: Filter by category
-
-**Example:**
-```typescript
-{
-  operation: 'query',
-  organizationId: 'org_123',
-  status: 'active',
-  paginationOpts: {
-    numItems: 10,
-    cursor: null
-  }
-}
-```
-
-### 4. update
-Update products with flexible filtering.
-
-**Required Parameters:**
-- Either `productId` OR `organizationId`
-- `updates`: Object containing fields to update
-
-**Optional Parameters:**
-- `externalId`: Filter by external ID
-- `status`: Filter by status
-- `category`: Filter by category
-
-**Example:**
-```typescript
-{
-  operation: 'update',
-  productId: 'prod_123',
-  updates: {
-    price: 1499,
-    status: 'active'
-  }
-}
-```
-
-### 5. filter
-Filter products using JEXL expressions. This operation loops through all products in the organization and evaluates the expression against each product. Products that match (expression evaluates to true) are returned.
-
-**Required Parameters:**
-- `organizationId`: Organization ID
-- `expression`: JEXL expression to evaluate
-
-**How it works:**
-1. Loops through all products using cursor-based iteration
-2. Evaluates the JEXL expression with each product as context
-3. Returns products where the expression evaluates to true
-
-**Expression Context:**
-The expression has access to all product fields:
-- `_id`: Product ID
-- `_creationTime`: Creation timestamp
-- `organizationId`: Organization ID
-- `name`: Product name
-- `description`: Product description
-- `imageUrl`: Product image URL
-- `stock`: Stock quantity
-- `price`: Product price
-- `currency`: Currency code
-- `category`: Product category
-- `tags`: Array of tags
-- `status`: Product status
-- `externalId`: External system ID
-- `metadata`: Additional metadata (can access nested fields)
-
-**Examples:**
-
-Filter by price:
-```typescript
-{
-  operation: 'filter',
-  organizationId: 'org_123',
-  expression: 'price > 100'
-}
-```
-
-Filter by status:
-```typescript
-{
-  operation: 'filter',
-  organizationId: 'org_123',
-  expression: 'status == "active"'
-}
-```
-
-Filter by multiple conditions:
-```typescript
-{
-  operation: 'filter',
-  organizationId: 'org_123',
-  expression: 'price > 50 && price < 200 && status == "active"'
-}
-```
-
-Filter by metadata field:
-```typescript
-{
-  operation: 'filter',
-  organizationId: 'org_123',
-  expression: 'metadata.featured == true'
-}
-```
-
-Filter by nested metadata:
-```typescript
-{
-  operation: 'filter',
-  organizationId: 'org_123',
-  expression: 'metadata.shopify && metadata.shopify.status == "active"'
-}
-```
-
-Filter by tags (array contains):
-```typescript
-{
-  operation: 'filter',
-  organizationId: 'org_123',
-  expression: 'tags && tags.includes("premium")'
-}
-```
-
-Filter by stock availability:
-```typescript
-{
-  operation: 'filter',
-  organizationId: 'org_123',
-  expression: 'stock > 0 && stock < 10'
-}
-```
-
-Complex filter with logical operators:
-```typescript
-{
-  operation: 'filter',
-  organizationId: 'org_123',
-  expression: '(category == "Electronics" || category == "Furniture") && price > 100'
-}
-```
-
-**Return Value:**
-```typescript
-{
-  operation: 'filter',
-  products: [...], // Array of matching products
-  count: 5,        // Number of matching products
-  timestamp: 1234567890
-}
-```
-
-**Performance Notes:**
-- Uses cursor-based iteration for efficient processing
-- Processes products one at a time to avoid memory issues
-- Continues processing even if one product fails evaluation
-- Errors are logged but don't stop the entire operation
-
-## JEXL Expression Syntax
-
-The filter operation uses JEXL (JavaScript Expression Language) for safe expression evaluation. JEXL supports:
-
-- **Comparisons**: `>`, `<`, `>=`, `<=`, `==`, `!=`
-- **Logical operators**: `&&`, `||`, `!`
-- **Math operations**: `+`, `-`, `*`, `/`, `%`
-- **Ternary operator**: `condition ? true_value : false_value`
-- **Array operations**: `array.includes(value)`, `array.length`
-- **Object access**: `object.field`, `object.nested.field`
-- **Null checks**: `field != null`, `field != undefined`
-
-See the [JEXL documentation](../../../../../../lib/variables/DESIGN.md) for more details.
-
-## Best Practices
-
-1. **Use indexes when possible**: For simple queries, prefer the `query` operation which uses Convex indexes for better performance.
-
-2. **Use filter for complex conditions**: Use the `filter` operation when you need to evaluate complex expressions that can't be expressed with simple index queries.
-
-3. **Test expressions**: Test your JEXL expressions with a small dataset first to ensure they work as expected.
-
-4. **Handle null values**: Always check for null/undefined when accessing optional fields:
-   ```typescript
-   expression: 'metadata && metadata.field == "value"'
-   ```
-
-5. **Use meaningful variable names**: Store filter results in workflow variables with descriptive names:
-   ```typescript
-   steps.filter_expensive_products.output.products
-   ```
-
-## See Also
-
-- [JEXL Expression Guide](../../../../../../lib/variables/DESIGN.md)
-- [Product Filter Example Workflow](../../../../../../workflows/examples/product-filter-example.ts)
-- [Workflow Developer Guide](../../../../../../docs/workflows/developer-guide.md)
-
diff --git a/services/platform/convex/workflow/actions/rag/README.md b/services/platform/convex/workflow/actions/rag/README.md
deleted file mode 100644
index 2b9d05964b..0000000000
--- a/services/platform/convex/workflow/actions/rag/README.md
+++ /dev/null
@@ -1,260 +0,0 @@
-# RAG Action - Document Upload to Cognee
-
-This action uploads documents from the Convex database to the cognee RAG (Retrieval-Augmented Generation) service for semantic search and retrieval.
-
-## Overview
-
-The RAG action enables workflows to:
-
-- Read documents from the Convex `documents` table
-- Handle both text content and file storage references
-- Upload documents to the cognee RAG service
-- Track upload status and results
-
-## Configuration
-
-### Environment Variables
-
-Set these in your `.env` file:
-
-```bash
-# RAG Service URL (default: http://localhost:8001)
-RAG_URL=http://localhost:8001
-
-# Optional: RAG API Key (if authentication is required)
-RAG_API_KEY=your-api-key-here
-```
-
-### Workflow Variables
-
-You can also configure RAG settings in workflow variables:
-
-```typescript
-{
-  ragServiceUrl: 'http://localhost:8001',
-  ragApiKey: 'optional-api-key',
-}
-```
-
-## Usage
-
-### Basic Example
-
-```typescript
-{
-  type: 'rag',
-  config: {
-    parameters: {
-      operation: 'upload_document',
-      documentId: 'doc_123',
-      organizationId: 'org_456',
-    },
-  },
-}
-```
-
-### With Custom RAG Service URL
-
-```typescript
-{
-  type: 'rag',
-  config: {
-    parameters: {
-      operation: 'upload_document',
-      documentId: 'doc_123',
-      organizationId: 'org_456',
-      ragServiceUrl: 'https://rag.example.com',
-    },
-  },
-}
-```
-
-### With Advanced Options
-
-```typescript
-{
-  type: 'rag',
-  config: {
-    parameters: {
-      operation: 'upload_document',
-      documentId: 'doc_123',
-      organizationId: 'org_456',
-      forceReupload: true,        // Re-upload even if already uploaded
-      includeMetadata: true,      // Include document metadata
-      timeout: 60000,             // 60 second timeout
-    },
-  },
-}
-```
-
-## Parameters
-
-| Parameter         | Type    | Required | Description                                         |
-| ----------------- | ------- | -------- | --------------------------------------------------- |
-| `operation`       | string  | Yes      | Must be `'upload_document'`                         |
-| `documentId`      | string  | Yes      | ID of the document to upload                        |
-| `organizationId`  | string  | Yes      | Organization ID for context                         |
-| `ragServiceUrl`   | string  | No       | RAG service URL (overrides env var)                 |
-| `forceReupload`   | boolean | No       | Re-upload even if already uploaded (default: false) |
-| `includeMetadata` | boolean | No       | Include document metadata (default: true)           |
-| `timeout`         | number  | No       | Request timeout in milliseconds (default: 30000)    |
-
-## Return Value
-
-The action returns a result object:
-
-```typescript
-{
-  success: boolean;
-  documentId: string;
-  ragDocumentId?: string;        // ID assigned by RAG service
-  chunksCreated?: number;        // Number of chunks created
-  processingTimeMs?: number;     // Time spent uploading
-  documentType?: 'text' | 'file'; // Type of document uploaded
-  executionTimeMs?: number;      // Total execution time
-  error?: string;                // Error message if failed
-  timestamp: number;             // Timestamp of upload
-}
-```
-
-## Document Types
-
-### Text Documents
-
-Documents with a `content` field are uploaded as text:
-
-```typescript
-{
-  title: 'My Document',
-  kind: 'note',
-  content: 'This is the document content...',
-  metadata: { /* ... */ }
-}
-```
-
-### File Documents
-
-Documents with a `fileId` field are uploaded as files:
-
-```typescript
-{
-  title: 'my-file.pdf',
-  kind: 'file',
-  fileId: 'storage_id_123',
-  metadata: {
-    contentType: 'application/pdf',
-    size: 1024000,
-    /* ... */
-  }
-}
-```
-
-## Metadata
-
-The action automatically includes the following metadata when uploading:
-
-```typescript
-{
-  documentId: string;           // Convex document ID
-  organizationId: string;       // Organization ID
-  title?: string;               // Document title
-  kind?: string;                // Document kind
-  sourceProvider?: string;      // Source provider (e.g., 'upload', 'onedrive')
-  uploadedAt: string;           // ISO timestamp
-}
-```
-
-## Error Handling
-
-The action handles various error scenarios:
-
-- **Document not found**: Returns error if document doesn't exist
-- **Missing content**: Returns error if document has neither content nor fileId
-- **File download failed**: Returns error if file URL is invalid or file is deleted
-- **RAG service unavailable**: Retries up to 3 times with exponential backoff
-- **Network timeout**: Respects the configured timeout parameter
-
-## Workflow Example
-
-Here's a complete workflow that uploads documents to RAG:
-
-```typescript
-export default {
-  workflowConfig: {
-    name: 'Upload Documents to RAG',
-    workflowType: 'predefined',
-    config: {
-      variables: {
-        ragServiceUrl: 'http://localhost:8001',
-      },
-    },
-  },
-  steps: [
-    {
-      id: 'trigger',
-      type: 'trigger',
-      config: { triggerType: 'manual' },
-    },
-    {
-      id: 'upload_to_rag',
-      type: 'action',
-      config: {
-        actionType: 'rag',
-        parameters: {
-          operation: 'upload_document',
-          documentId: '${trigger.documentId}',
-          organizationId: '${trigger.organizationId}',
-        },
-      },
-    },
-  ],
-};
-```
-
-## Troubleshooting
-
-### RAG Service URL not configured
-
-**Error**: "RAG service URL not configured"
-
-**Solution**: Set `RAG_URL` environment variable or provide `ragServiceUrl` in action parameters.
-
-### Document not found
-
-**Error**: "Document not found"
-
-**Solution**: Verify the `documentId` is correct and the document exists in the database.
-
-### File URL not available
-
-**Error**: "File URL not available for document"
-
-**Solution**: The file may have been deleted from storage. Check if the file still exists in Convex storage.
-
-### RAG service connection failed
-
-**Error**: "RAG service error: 502 Bad Gateway"
-
-**Solution**: Verify the RAG service is running and accessible at the configured URL.
-
-## Implementation Details
-
-### File Structure
-
-```
-rag/
-├── rag_action.ts          # Main action definition
-├── types.ts               # TypeScript interfaces
-├── rag_client.ts          # HTTP client for RAG service
-├── get_rag_config.ts      # Configuration helper
-├── read_document.ts       # Document reading logic
-└── README.md              # This file
-```
-
-### Key Features
-
-- **Retry Logic**: Automatic retries with exponential backoff for transient failures
-- **File Handling**: Seamless handling of both text and file documents
-- **Metadata Enrichment**: Automatic metadata inclusion for better RAG context
-- **Error Tracking**: Detailed error messages for debugging
-- **Performance Metrics**: Tracks processing and execution times
diff --git a/services/platform/convex/workflow/actions/rag/get_document_info.ts b/services/platform/convex/workflow/actions/rag/helpers/get_document_info.ts
similarity index 59%
rename from services/platform/convex/workflow/actions/rag/get_document_info.ts
rename to services/platform/convex/workflow/actions/rag/helpers/get_document_info.ts
index 32b8da20cd..a983eb281c 100644
--- a/services/platform/convex/workflow/actions/rag/get_document_info.ts
+++ b/services/platform/convex/workflow/actions/rag/helpers/get_document_info.ts
@@ -1,7 +1,7 @@
 import type { RagActionParams } from './types';
-import type { ActionCtx } from '../../../_generated/server';
-import { api, internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { api, internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 
 /**
  * Document information without downloading content
@@ -25,22 +25,25 @@ export async function getDocumentInfo(
   ctx: ActionCtx,
   params: Extract<RagActionParams, { operation: 'upload_document' }>,
 ): Promise<DocumentInfo> {
-  if (!params.documentId) {
-    throw new Error('documentId is required');
+  if (!params.recordId) {
+    throw new Error('recordId is required');
   }
 
   const getDocumentResult = await ctx.runQuery?.(
     internal.documents.getDocumentById,
     {
-      documentId: params.documentId as Id<'documents'>,
+      documentId: params.recordId as Id<'documents'>,
     },
   );
 
   if (!getDocumentResult) {
-    throw new Error(`Document not found: ${params.documentId}`);
+    throw new Error(`Document not found: ${params.recordId}`);
   }
 
   const document = getDocumentResult as Record<string, unknown>;
+  const baseMetadata =
+    (document.metadata as Record<string, unknown> | undefined) || {};
+  const organizationId = document.organizationId as string | undefined;
 
   // Check if document has file content
   if (document.fileId) {
@@ -49,24 +52,23 @@ export async function getDocumentInfo(
     });
 
     if (!fileUrl) {
-      throw new Error(
-        `File URL not available for document ${params.documentId}`,
-      );
+      throw new Error(`File URL not available for document ${params.recordId}`);
     }
 
-    const metadata = (document.metadata as Record<string, unknown>) || {};
     return {
       type: 'file',
       fileUrl: fileUrl as string,
       filename:
-        (metadata.name as string) || (document.title as string) || 'document',
+        (baseMetadata.name as string) ||
+        (document.title as string) ||
+        'document',
       contentType:
-        (metadata.contentType as string) || 'application/octet-stream',
+        (baseMetadata.contentType as string) || 'application/octet-stream',
       metadata: {
-        documentId: params.documentId,
-        organizationId: params.organizationId,
+        recordId: params.recordId,
+        organizationId,
         title: document.title as string,
-        ...metadata,
+        ...baseMetadata,
       },
     };
   }
@@ -77,13 +79,14 @@ export async function getDocumentInfo(
       type: 'text',
       content: document.content as string,
       metadata: {
-        documentId: params.documentId,
-        organizationId: params.organizationId,
+        recordId: params.recordId,
+        organizationId,
         title: document.title as string,
-        ...((document.metadata as Record<string, unknown>) || {}),
+        ...baseMetadata,
       },
     };
   }
 
-  throw new Error(`Document has no content or file: ${params.documentId}`);
+  throw new Error(`Document has no content or file: ${params.recordId}`);
 }
+
diff --git a/services/platform/convex/workflow/actions/rag/get_rag_config.ts b/services/platform/convex/workflow/actions/rag/helpers/get_rag_config.ts
similarity index 99%
rename from services/platform/convex/workflow/actions/rag/get_rag_config.ts
rename to services/platform/convex/workflow/actions/rag/helpers/get_rag_config.ts
index 05205bcf52..f7800ac5f7 100644
--- a/services/platform/convex/workflow/actions/rag/get_rag_config.ts
+++ b/services/platform/convex/workflow/actions/rag/helpers/get_rag_config.ts
@@ -13,3 +13,4 @@ export function getRagConfig(): RagConfig {
 
   return { serviceUrl };
 }
+
diff --git a/services/platform/convex/workflow/actions/rag/types.ts b/services/platform/convex/workflow/actions/rag/helpers/types.ts
similarity index 84%
rename from services/platform/convex/workflow/actions/rag/types.ts
rename to services/platform/convex/workflow/actions/rag/helpers/types.ts
index 93348b7ff4..797f38872f 100644
--- a/services/platform/convex/workflow/actions/rag/types.ts
+++ b/services/platform/convex/workflow/actions/rag/helpers/types.ts
@@ -4,17 +4,14 @@
 export type RagActionParams =
   | {
       operation: 'upload_document';
-      documentId: string;
-      organizationId: string;
-      forceReupload?: boolean;
-      includeMetadata?: boolean;
-      timeout?: number;
+      recordId: string;
     }
   | {
       operation: 'upload_text';
+      /** Optional for upload_text; when provided, also used as endpoint document_id. */
+      recordId?: string;
       content: string;
       metadata: Record<string, unknown>;
-      timeout?: number;
     };
 
 /**
@@ -34,8 +31,8 @@ export interface DocumentContent {
 export interface RagUploadResult {
   /** Whether the request to RAG succeeded (enqueue + basic validation). */
   success: boolean;
-  /** Caller-level document identifier (usually from metadata.documentId). */
-  documentId: string;
+  /** Caller-level record identifier (usually from metadata.recordId). */
+  recordId: string;
   /** Identifier returned by the RAG service for the ingested/queued document. */
   ragDocumentId?: string;
   /** Number of chunks created. For async ingestion this will typically be 0. */
@@ -55,3 +52,4 @@ export interface RagUploadResult {
   /** Background job identifier if provided by the RAG service. */
   jobId?: string;
 }
+
diff --git a/services/platform/convex/workflow/actions/rag/upload_file_direct.ts b/services/platform/convex/workflow/actions/rag/helpers/upload_file_direct.ts
similarity index 77%
rename from services/platform/convex/workflow/actions/rag/upload_file_direct.ts
rename to services/platform/convex/workflow/actions/rag/helpers/upload_file_direct.ts
index 2326a2775e..0d9c066db7 100644
--- a/services/platform/convex/workflow/actions/rag/upload_file_direct.ts
+++ b/services/platform/convex/workflow/actions/rag/helpers/upload_file_direct.ts
@@ -1,5 +1,14 @@
 import type { RagUploadResult } from './types';
 
+export interface UploadFileDirectArgs {
+  ragServiceUrl: string;
+  fileUrl: string;
+  filename: string;
+  contentType: string;
+  metadata?: Record<string, unknown>;
+  timeoutMs?: number;
+}
+
 /**
  * Upload file document to RAG service by downloading from URL and uploading directly
  *
@@ -7,14 +16,14 @@ import type { RagUploadResult } from './types';
  * to the RAG service using multipart/form-data, which is more reliable than
  * having the RAG service fetch from a URL.
  */
-export async function uploadFileDirect(
-  ragServiceUrl: string,
-  fileUrl: string,
-  filename: string,
-  contentType: string,
-  metadata?: Record<string, unknown>,
-  timeout = 30000,
-): Promise<RagUploadResult> {
+export async function uploadFileDirect({
+  ragServiceUrl,
+  fileUrl,
+  filename,
+  contentType,
+  metadata,
+  timeoutMs = 30000,
+}: UploadFileDirectArgs): Promise<RagUploadResult> {
   const startTime = Date.now();
 
   // Step 1: Download file from Convex storage
@@ -42,16 +51,16 @@ export async function uploadFileDirect(
     formData.append('metadata', JSON.stringify(enrichedMetadata));
   }
 
-  // Add document_id if provided in metadata
-  if (metadata?.documentId) {
-    formData.append('document_id', metadata.documentId as string);
+  // Add document_id if provided in metadata (mapped from recordId)
+  if (metadata?.recordId) {
+    formData.append('document_id', metadata.recordId as string);
   }
 
   // Step 3: Upload to RAG service
   const url = `${ragServiceUrl}/api/v1/documents/upload`;
 
   const controller = new AbortController();
-  const timeoutId = setTimeout(() => controller.abort(), timeout);
+  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
 
   const response = await fetch(url, {
     method: 'POST',
@@ -74,7 +83,7 @@ export async function uploadFileDirect(
 
   return {
     success: (result.success as boolean | undefined) ?? true,
-    documentId: (metadata?.documentId as string) || ragDocumentId || 'unknown',
+    recordId: (metadata?.recordId as string) || ragDocumentId || 'unknown',
     ragDocumentId,
     chunksCreated: (result.chunks_created as number) || 0,
     processingTimeMs: Date.now() - startTime,
@@ -83,3 +92,4 @@ export async function uploadFileDirect(
     jobId,
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/rag/upload_text_document.ts b/services/platform/convex/workflow/actions/rag/helpers/upload_text_document.ts
similarity index 64%
rename from services/platform/convex/workflow/actions/rag/upload_text_document.ts
rename to services/platform/convex/workflow/actions/rag/helpers/upload_text_document.ts
index e5e182df5f..1a450e4dcd 100644
--- a/services/platform/convex/workflow/actions/rag/upload_text_document.ts
+++ b/services/platform/convex/workflow/actions/rag/helpers/upload_text_document.ts
@@ -1,25 +1,40 @@
 import type { RagUploadResult } from './types';
 
+export interface UploadTextDocumentArgs {
+  ragServiceUrl: string;
+  content: string;
+  metadata?: Record<string, unknown>;
+  /** Optional logical record identifier; sent as `document_id` to the RAG endpoint. */
+  recordId?: string;
+  timeoutMs?: number;
+}
+
 /**
  * Upload text document to RAG service
  */
-export async function uploadTextDocument(
-  ragServiceUrl: string,
-  content: string,
-  metadata?: Record<string, unknown>,
-  timeout = 30000,
-): Promise<RagUploadResult> {
+export async function uploadTextDocument({
+  ragServiceUrl,
+  content,
+  metadata,
+  recordId,
+  timeoutMs = 30000,
+}: UploadTextDocumentArgs): Promise<RagUploadResult> {
   const startTime = Date.now();
   const url = `${ragServiceUrl}/api/v1/documents`;
 
-  const payload = {
+  const payload: Record<string, unknown> = {
     content,
     content_type: 'text',
     metadata: metadata || {},
   };
 
+  // If a logical recordId is provided, also use it as the endpoint document_id
+  if (recordId) {
+    payload.document_id = recordId;
+  }
+
   const controller = new AbortController();
-  const timeoutId = setTimeout(() => controller.abort(), timeout);
+  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
 
   const response = await fetch(url, {
     method: 'POST',
@@ -45,7 +60,8 @@ export async function uploadTextDocument(
 
   return {
     success: (result.success as boolean | undefined) ?? true,
-    documentId: (metadata?.documentId as string) || ragDocumentId || 'unknown',
+    recordId:
+      recordId || (metadata?.recordId as string) || ragDocumentId || 'unknown',
     ragDocumentId,
     chunksCreated: (result.chunks_created as number) || 0,
     processingTimeMs: Date.now() - startTime,
@@ -54,3 +70,4 @@ export async function uploadTextDocument(
     jobId,
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/rag/rag_action.ts b/services/platform/convex/workflow/actions/rag/rag_action.ts
index f059e39956..d3848c432b 100644
--- a/services/platform/convex/workflow/actions/rag/rag_action.ts
+++ b/services/platform/convex/workflow/actions/rag/rag_action.ts
@@ -1,10 +1,10 @@
 import { v } from 'convex/values';
 import type { ActionDefinition } from '../../helpers/nodes/action/types';
-import type { RagActionParams, RagUploadResult } from './types';
-import { getRagConfig } from './get_rag_config';
-import { getDocumentInfo } from './get_document_info';
-import { uploadTextDocument } from './upload_text_document';
-import { uploadFileDirect } from './upload_file_direct';
+import type { RagActionParams, RagUploadResult } from './helpers/types';
+import { getRagConfig } from './helpers/get_rag_config';
+import { getDocumentInfo } from './helpers/get_document_info';
+import { uploadTextDocument } from './helpers/upload_text_document';
+import { uploadFileDirect } from './helpers/upload_file_direct';
 
 export const ragAction: ActionDefinition<RagActionParams> = {
   type: 'rag',
@@ -15,17 +15,13 @@ export const ragAction: ActionDefinition<RagActionParams> = {
   parametersValidator: v.union(
     v.object({
       operation: v.literal('upload_document'),
-      documentId: v.string(),
-      organizationId: v.string(),
-      forceReupload: v.optional(v.boolean()),
-      includeMetadata: v.optional(v.boolean()),
-      timeout: v.optional(v.number()),
+      recordId: v.string(),
     }),
     v.object({
       operation: v.literal('upload_text'),
+      recordId: v.optional(v.string()),
       content: v.string(),
       metadata: v.any(),
-      timeout: v.optional(v.number()),
     }),
   ),
 
@@ -41,13 +37,13 @@ export const ragAction: ActionDefinition<RagActionParams> = {
     let documentType: string;
 
     if (processedParams.operation === 'upload_text') {
-      // Direct text upload
-      uploadResult = await uploadTextDocument(
-        ragConfig.serviceUrl,
-        processedParams.content,
-        processedParams.metadata,
-        processedParams.timeout || 30000,
-      );
+      // Direct text upload; metadata is passed through as provided
+      uploadResult = await uploadTextDocument({
+        ragServiceUrl: ragConfig.serviceUrl,
+        content: processedParams.content,
+        metadata: processedParams.metadata as Record<string, unknown>,
+        recordId: processedParams.recordId,
+      });
       documentType = 'text';
     } else {
       // Document upload (from documents table)
@@ -55,26 +51,20 @@ export const ragAction: ActionDefinition<RagActionParams> = {
 
       if (documentInfo.type === 'text') {
         // Upload text content directly
-        uploadResult = await uploadTextDocument(
-          ragConfig.serviceUrl,
-          documentInfo.content as string,
-          processedParams.includeMetadata !== false
-            ? documentInfo.metadata
-            : undefined,
-          processedParams.timeout || 30000,
-        );
+        uploadResult = await uploadTextDocument({
+          ragServiceUrl: ragConfig.serviceUrl,
+          content: documentInfo.content as string,
+          metadata: documentInfo.metadata,
+        });
       } else {
         // Upload file directly by downloading from storage and uploading to RAG
-        uploadResult = await uploadFileDirect(
-          ragConfig.serviceUrl,
-          documentInfo.fileUrl as string,
-          documentInfo.filename || 'document',
-          documentInfo.contentType || 'application/octet-stream',
-          processedParams.includeMetadata !== false
-            ? documentInfo.metadata
-            : undefined,
-          processedParams.timeout || 30000,
-        );
+        uploadResult = await uploadFileDirect({
+          ragServiceUrl: ragConfig.serviceUrl,
+          fileUrl: documentInfo.fileUrl as string,
+          filename: documentInfo.filename || 'document',
+          contentType: documentInfo.contentType || 'application/octet-stream',
+          metadata: documentInfo.metadata,
+        });
       }
       documentType = documentInfo.type;
     }
diff --git a/services/platform/convex/workflow/actions/website/types.ts b/services/platform/convex/workflow/actions/website/helpers/types.ts
similarity index 100%
rename from services/platform/convex/workflow/actions/website/types.ts
rename to services/platform/convex/workflow/actions/website/helpers/types.ts
diff --git a/services/platform/convex/workflow/actions/website/website_action.ts b/services/platform/convex/workflow/actions/website/website_action.ts
index 55a6690e25..cfdcdac235 100644
--- a/services/platform/convex/workflow/actions/website/website_action.ts
+++ b/services/platform/convex/workflow/actions/website/website_action.ts
@@ -1,6 +1,6 @@
 import { v } from 'convex/values';
 import type { ActionDefinition } from '../../helpers/nodes/action/types';
-import type { WebsiteActionParams } from './types';
+import type { WebsiteActionParams } from './helpers/types';
 import { internal } from '../../../_generated/api';
 import type { Id } from '../../../_generated/dataModel';
 
diff --git a/services/platform/convex/workflow/actions/websitePages/types.ts b/services/platform/convex/workflow/actions/websitePages/helpers/types.ts
similarity index 99%
rename from services/platform/convex/workflow/actions/websitePages/types.ts
rename to services/platform/convex/workflow/actions/websitePages/helpers/types.ts
index 0f0807181d..958c1c2d36 100644
--- a/services/platform/convex/workflow/actions/websitePages/types.ts
+++ b/services/platform/convex/workflow/actions/websitePages/helpers/types.ts
@@ -27,3 +27,4 @@ export interface WebsitePagesActionResult {
   success: boolean;
   timestamp: number;
 }
+
diff --git a/services/platform/convex/workflow/actions/websitePages/websitePages_action.ts b/services/platform/convex/workflow/actions/websitePages/websitePages_action.ts
index e5c199edac..29dbe94579 100644
--- a/services/platform/convex/workflow/actions/websitePages/websitePages_action.ts
+++ b/services/platform/convex/workflow/actions/websitePages/websitePages_action.ts
@@ -1,6 +1,6 @@
 import { v } from 'convex/values';
 import type { ActionDefinition } from '../../helpers/nodes/action/types';
-import type { WebsitePagesActionParams } from './types';
+import type { WebsitePagesActionParams } from './helpers/types';
 import { internal } from '../../../_generated/api';
 import type { Id } from '../../../_generated/dataModel';
 
diff --git a/services/platform/convex/workflow/actions/workflow/types.ts b/services/platform/convex/workflow/actions/workflow/helpers/types.ts
similarity index 99%
rename from services/platform/convex/workflow/actions/workflow/types.ts
rename to services/platform/convex/workflow/actions/workflow/helpers/types.ts
index 35b0f69678..d7dfa44d5a 100644
--- a/services/platform/convex/workflow/actions/workflow/types.ts
+++ b/services/platform/convex/workflow/actions/workflow/helpers/types.ts
@@ -23,3 +23,4 @@ export interface UploadAllWorkflowsResult {
   }>;
   executionTimeMs?: number;
 }
+
diff --git a/services/platform/convex/workflow/actions/workflow/upload_workflows.ts b/services/platform/convex/workflow/actions/workflow/helpers/upload_workflows.ts
similarity index 84%
rename from services/platform/convex/workflow/actions/workflow/upload_workflows.ts
rename to services/platform/convex/workflow/actions/workflow/helpers/upload_workflows.ts
index cc0167d1ae..ea1ce0c4c4 100644
--- a/services/platform/convex/workflow/actions/workflow/upload_workflows.ts
+++ b/services/platform/convex/workflow/actions/workflow/helpers/upload_workflows.ts
@@ -1,9 +1,9 @@
 import type { UploadAllWorkflowsResult } from './types';
-import * as workflowExports from '../../../predefined_workflows';
-import { getRagConfig } from '../rag/get_rag_config';
-import { uploadTextDocument } from '../rag/upload_text_document';
+import * as workflowExports from '../../../../predefined_workflows';
+import { getRagConfig } from '../../rag/helpers/get_rag_config';
+import { uploadTextDocument } from '../../rag/helpers/upload_text_document';
 
-import { createDebugLog } from '../../../lib/debug_log';
+import { createDebugLog } from '../../../../lib/debug_log';
 
 const debugLog = createDebugLog('DEBUG_WORKFLOW', '[Workflow]');
 
@@ -50,11 +50,11 @@ export async function uploadAllWorkflows(
       (workflowConfig?.workflowType as string) || 'predefined';
 
     // Upload to RAG service
-    const result = await uploadTextDocument(
-      ragConfig.serviceUrl,
+    const result = await uploadTextDocument({
+      ragServiceUrl: ragConfig.serviceUrl,
       content,
-      {
-        documentId: `workflow_${key}`,
+      metadata: {
+        recordId: `workflow_${key}`,
         workflowKey: key,
         workflowName: workflowName,
         workflowDescription: workflowDescription,
@@ -63,8 +63,8 @@ export async function uploadAllWorkflows(
         organizationId: organizationId,
         uploadedAt: Date.now(),
       },
-      timeout,
-    );
+      timeoutMs: timeout,
+    });
 
     debugLog(
       `Workflow RAG Upload ✓ Successfully uploaded: ${key} (${result.chunksCreated} chunks)`,
@@ -89,3 +89,4 @@ export async function uploadAllWorkflows(
     details,
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/workflow/workflow_action.ts b/services/platform/convex/workflow/actions/workflow/workflow_action.ts
index 05af9bf26e..2c67356463 100644
--- a/services/platform/convex/workflow/actions/workflow/workflow_action.ts
+++ b/services/platform/convex/workflow/actions/workflow/workflow_action.ts
@@ -1,7 +1,7 @@
 import { v } from 'convex/values';
 import type { ActionDefinition } from '../../helpers/nodes/action/types';
-import type { WorkflowActionParams } from './types';
-import { uploadAllWorkflows } from './upload_workflows';
+import type { WorkflowActionParams } from './helpers/types';
+import { uploadAllWorkflows } from './helpers/upload_workflows';
 
 export const workflowAction: ActionDefinition<WorkflowActionParams> = {
   type: 'workflow',
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/find_product_recommendation_by_status.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status.ts
similarity index 80%
rename from services/platform/convex/workflow/actions/workflow_processing_records/find_product_recommendation_by_status.ts
rename to services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status.ts
index da55283091..983110466a 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/find_product_recommendation_by_status.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status.ts
@@ -1,9 +1,9 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
 
 import type { FindUnprocessedResult } from './types';
 
-import { createDebugLog } from '../../../lib/debug_log';
+import { createDebugLog } from '../../../../lib/debug_log';
 
 const debugLog = createDebugLog('DEBUG_WORKFLOW', '[Workflow]');
 
@@ -32,3 +32,4 @@ export async function findProductRecommendationByStatus(
     count: result.count,
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/find_unprocessed.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed.ts
similarity index 83%
rename from services/platform/convex/workflow/actions/workflow_processing_records/find_unprocessed.ts
rename to services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed.ts
index 25b1086c8e..bf34e5ca2c 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/find_unprocessed.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed.ts
@@ -1,5 +1,5 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
 
 import type { TableName, FindUnprocessedResult } from './types';
 
@@ -27,3 +27,4 @@ export async function findUnprocessed(
     count: result.count,
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/find_unprocessed_open_conversation.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation.ts
similarity index 83%
rename from services/platform/convex/workflow/actions/workflow_processing_records/find_unprocessed_open_conversation.ts
rename to services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation.ts
index ec5ad1634a..a7f609d795 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/find_unprocessed_open_conversation.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation.ts
@@ -1,5 +1,5 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
 
 import type { FindUnprocessedResult } from './types';
 
@@ -25,3 +25,4 @@ export async function findUnprocessedOpenConversation(
     count: result.count,
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/record_processed.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/record_processed.ts
similarity index 82%
rename from services/platform/convex/workflow/actions/workflow_processing_records/record_processed.ts
rename to services/platform/convex/workflow/actions/workflow_processing_records/helpers/record_processed.ts
index f2af761ba4..36edd7ca47 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/record_processed.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/record_processed.ts
@@ -1,6 +1,6 @@
-import type { ActionCtx } from '../../../_generated/server';
-import { internal } from '../../../_generated/api';
-import type { Id } from '../../../_generated/dataModel';
+import type { ActionCtx } from '../../../../_generated/server';
+import { internal } from '../../../../_generated/api';
+import type { Id } from '../../../../_generated/dataModel';
 import type { TableName, RecordProcessedResult } from './types';
 
 export async function recordProcessed(
@@ -33,3 +33,4 @@ export async function recordProcessed(
     timestamp: Date.now(),
   };
 }
+
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/types.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/types.ts
similarity index 87%
rename from services/platform/convex/workflow/actions/workflow_processing_records/types.ts
rename to services/platform/convex/workflow/actions/workflow_processing_records/helpers/types.ts
index e63bc20068..5698febdd4 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/types.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/types.ts
@@ -1,4 +1,4 @@
-import type { Id } from '../../../_generated/dataModel';
+import type { Id } from '../../../../_generated/dataModel';
 
 export type TableName =
   | 'customers'
@@ -21,3 +21,4 @@ export type RecordProcessedResult = {
   success: boolean;
   timestamp: number;
 };
+
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/workflow_processing_records_action.ts b/services/platform/convex/workflow/actions/workflow_processing_records/workflow_processing_records_action.ts
index eb9286ab5c..ea178af0f7 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/workflow_processing_records_action.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/workflow_processing_records_action.ts
@@ -12,11 +12,11 @@
 import { v } from 'convex/values';
 import type { ActionDefinition } from '../../helpers/nodes/action/types';
 
-import { findUnprocessed } from './find_unprocessed';
-import { findUnprocessedOpenConversation } from './find_unprocessed_open_conversation';
-import { findProductRecommendationByStatus } from './find_product_recommendation_by_status';
-import { recordProcessed } from './record_processed';
-import type { TableName } from './types';
+import { findUnprocessed } from './helpers/find_unprocessed';
+import { findUnprocessedOpenConversation } from './helpers/find_unprocessed_open_conversation';
+import { findProductRecommendationByStatus } from './helpers/find_product_recommendation_by_status';
+import { recordProcessed } from './helpers/record_processed';
+import type { TableName } from './helpers/types';
 
 export const workflowProcessingRecordsAction: ActionDefinition<{
   operation:

From db1f410369028d5b443540ef85a17c2f0836c9f7 Mon Sep 17 00:00:00 2001
From: larryro <371767072@qq.com>
Date: Wed, 3 Dec 2025 18:03:23 +0800
Subject: [PATCH 2/3] refactor(convex): rename workflow processing fields for
 clarity

- Rename `documentId` to `recordId` across workflow processing records
- Rename `documentCreationTime` to `recordCreationTime`
- Rename `workflowId` to `wfDefinitionId` for consistency with schema
- Add `rootWfDefinitionId` to wfExecutions for tracking workflow family versions
- Update schema indexes: `by_document` -> `by_record`, `by_org_table_workflow_*` -> `by_org_table_wfDefinition_*`
- Update predefined workflows to use `{{rootWfDefinitionId}}` instead of `{{workflowId}}`
- Change default RAG sync schedules from hourly to every 20 minutes
- Remove unused `create_execution.ts` and related types
- Rename helper function `isDocumentProcessed` to `isRecordProcessed`
---
 services/platform/convex/_generated/api.d.ts  |  2 -
 .../workflows/action_reference.ts             |  8 +--
 .../convex/lib/create_workflow_agent.ts       |  6 +-
 .../organizations/save_default_workflows.ts   | 16 ++---
 .../model/wf_executions/create_execution.ts   | 63 -------------------
 .../convex/model/wf_executions/index.ts       |  1 -
 .../convex/model/wf_executions/types.ts       | 22 -------
 .../find_product_recommendation_by_status.ts  |  7 +--
 .../find_unprocessed.ts                       |  7 ++-
 .../find_unprocessed_open_conversation.ts     |  6 +-
 .../find_unprocessed_with_custom_query.ts     |  6 +-
 .../get_latest_processed_creation_time.ts     | 16 ++---
 .../helpers/is_document_processed.ts          | 34 +++++-----
 .../helpers/run_query.ts                      | 14 ++---
 .../workflow_processing_records/index.ts      |  4 +-
 .../record_processed.ts                       | 26 ++++----
 .../workflow_processing_records/types.ts      |  2 +-
 .../conversation_auto_reply.ts                |  8 +--
 .../predefined_workflows/customer_rag_sync.ts |  8 +--
 .../predefined_workflows/document_rag_sync.ts |  8 +--
 .../general_customer_status_assessment.ts     |  8 +--
 .../general_product_recommendation.ts         | 10 +--
 .../loopi_customer_status_assessment.ts       |  8 +--
 .../loopi_product_recommendation.ts           | 10 +--
 .../predefined_workflows/onedrive_sync.ts     |  8 +--
 .../predefined_workflows/product_rag_sync.ts  |  8 +--
 .../product_recommendation_email.ts           |  8 +--
 .../product_relationship_analysis.ts          |  8 +--
 .../website_pages_rag_sync.ts                 |  8 +--
 services/platform/convex/schema.ts            | 27 ++++----
 .../find_product_recommendation_by_status.ts  |  5 +-
 .../helpers/find_unprocessed.ts               |  5 +-
 .../find_unprocessed_open_conversation.ts     |  5 +-
 .../helpers/record_processed.ts               | 32 +++++-----
 .../workflow_processing_records_action.ts     | 32 +++++-----
 .../helpers/engine/start_workflow_handler.ts  | 13 ++--
 .../initialize_execution_variables.ts         | 15 +++--
 .../workflow/helpers/step_execution/types.ts  |  1 +
 .../convex/workflow_processing_records.ts     | 26 ++++----
 39 files changed, 211 insertions(+), 290 deletions(-)
 delete mode 100644 services/platform/convex/model/wf_executions/create_execution.ts

diff --git a/services/platform/convex/_generated/api.d.ts b/services/platform/convex/_generated/api.d.ts
index 8ed5292afe..304ed5e9ae 100644
--- a/services/platform/convex/_generated/api.d.ts
+++ b/services/platform/convex/_generated/api.d.ts
@@ -347,7 +347,6 @@ import type * as model_wf_definitions_update_draft from "../model/wf_definitions
 import type * as model_wf_definitions_update_workflow from "../model/wf_definitions/update_workflow.js";
 import type * as model_wf_definitions_update_workflow_status from "../model/wf_definitions/update_workflow_status.js";
 import type * as model_wf_executions_complete_execution from "../model/wf_executions/complete_execution.js";
-import type * as model_wf_executions_create_execution from "../model/wf_executions/create_execution.js";
 import type * as model_wf_executions_fail_execution from "../model/wf_executions/fail_execution.js";
 import type * as model_wf_executions_get_execution from "../model/wf_executions/get_execution.js";
 import type * as model_wf_executions_get_execution_step_journal from "../model/wf_executions/get_execution_step_journal.js";
@@ -938,7 +937,6 @@ declare const fullApi: ApiFromModules<{
   "model/wf_definitions/update_workflow": typeof model_wf_definitions_update_workflow;
   "model/wf_definitions/update_workflow_status": typeof model_wf_definitions_update_workflow_status;
   "model/wf_executions/complete_execution": typeof model_wf_executions_complete_execution;
-  "model/wf_executions/create_execution": typeof model_wf_executions_create_execution;
   "model/wf_executions/fail_execution": typeof model_wf_executions_fail_execution;
   "model/wf_executions/get_execution": typeof model_wf_executions_get_execution;
   "model/wf_executions/get_execution_step_journal": typeof model_wf_executions_get_execution_step_journal;
diff --git a/services/platform/convex/agent_tools/convex_tools/workflows/action_reference.ts b/services/platform/convex/agent_tools/convex_tools/workflows/action_reference.ts
index a8a1e41f47..ce6de0a7dc 100644
--- a/services/platform/convex/agent_tools/convex_tools/workflows/action_reference.ts
+++ b/services/platform/convex/agent_tools/convex_tools/workflows/action_reference.ts
@@ -429,13 +429,13 @@ export const ACTION_REFERENCE: ActionReference[] = [
           'operation',
           'organizationId',
           'tableName',
-          'documentId',
-          'workflowId',
-          'documentCreationTime',
+          'recordId',
+          'wfDefinitionId',
+          'recordCreationTime',
         ],
         optionalParams: ['metadata'],
         example:
-          '{ action: "workflow_processing_records", parameters: { operation: "record_processed", organizationId: "{{organizationId}}", tableName: "customers", documentId: "{{customerId}}", workflowId: "{{workflowId}}", documentCreationTime: {{customer._creationTime}} } }',
+          '{ action: "workflow_processing_records", parameters: { operation: "record_processed", organizationId: "{{organizationId}}", tableName: "customers", recordId: "{{customerId}}", wfDefinitionId: "{{wfDefinitionId}}", recordCreationTime: {{customer._creationTime}} } }',
       },
     ],
   },
diff --git a/services/platform/convex/lib/create_workflow_agent.ts b/services/platform/convex/lib/create_workflow_agent.ts
index b5e1b1d352..d387abb417 100644
--- a/services/platform/convex/lib/create_workflow_agent.ts
+++ b/services/platform/convex/lib/create_workflow_agent.ts
@@ -280,9 +280,9 @@ REMINDER: All of these are action steps with stepType: "action". The "type" fiel
     operation: 'record_processed',
     organizationId: '{{organizationId}}',
     tableName: 'customers',
-    workflowId: '{{workflowId}}',
-    documentId: '{{entityId}}',
-    documentCreationTime: '{{entity._creationTime}}',
+    wfDefinitionId: '{{wfDefinitionId}}',
+    recordId: '{{entityId}}',
+    recordCreationTime: '{{entity._creationTime}}',
     metadata: { processedAt: '{{now}}' }
   }
 }
diff --git a/services/platform/convex/model/organizations/save_default_workflows.ts b/services/platform/convex/model/organizations/save_default_workflows.ts
index 94b88d6982..86fcaa18c8 100644
--- a/services/platform/convex/model/organizations/save_default_workflows.ts
+++ b/services/platform/convex/model/organizations/save_default_workflows.ts
@@ -26,11 +26,11 @@ interface SaveDefaultWorkflowsArgs {
  * Save default workflows for a new organization
  *
  * This includes:
- * - Document RAG Sync (scheduled every hour)
+ * - Document RAG Sync (scheduled every 20 minutes)
  * - OneDrive Sync (scheduled every hour)
- * - Product RAG Sync (scheduled every hour)
- * - Website Pages RAG Sync (scheduled every hour)
- * - Customer RAG Sync (scheduled every hour)
+ * - Product RAG Sync (scheduled every 20 minutes)
+ * - Website Pages RAG Sync (scheduled every 20 minutes)
+ * - Customer RAG Sync (scheduled every 20 minutes)
  */
 export async function saveDefaultWorkflows(
   ctx: ActionCtx,
@@ -46,7 +46,7 @@ export async function saveDefaultWorkflows(
   const workflowsToSave = [
     {
       workflow: documentRagSync,
-      schedule: '0 */1 * * *', // Every hour
+      schedule: '*/20 * * * *', // Every 20 minutes
       timezone: 'UTC',
     },
     {
@@ -56,17 +56,17 @@ export async function saveDefaultWorkflows(
     },
     {
       workflow: productRagSync,
-      schedule: '0 */1 * * *', // Every hour
+      schedule: '*/20 * * * *', // Every 20 minutes
       timezone: 'UTC',
     },
     {
       workflow: websitePagesRagSync,
-      schedule: '0 */1 * * *', // Every hour
+      schedule: '*/20 * * * *', // Every 20 minutes
       timezone: 'UTC',
     },
     {
       workflow: customerRagSync,
-      schedule: '0 */1 * * *', // Every hour
+      schedule: '*/20 * * * *', // Every 20 minutes
       timezone: 'UTC',
     },
     {
diff --git a/services/platform/convex/model/wf_executions/create_execution.ts b/services/platform/convex/model/wf_executions/create_execution.ts
deleted file mode 100644
index 9f0b252072..0000000000
--- a/services/platform/convex/model/wf_executions/create_execution.ts
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Create execution record
- */
-
-import type { MutationCtx } from '../../_generated/server';
-import type { Id } from '../../_generated/dataModel';
-// Inline serialization removed. Variables are initialized empty at creation; actual values set from actions.
-import { snakeCase } from 'lodash';
-import type { CreateExecutionArgs, ExecutionVariables } from './types';
-
-import { createDebugLog } from '../../lib/debug_log';
-
-const debugLog = createDebugLog('DEBUG_WORKFLOW', '[Workflow]');
-
-export async function createExecution(
-  ctx: MutationCtx,
-  args: CreateExecutionArgs,
-): Promise<Id<'wfExecutions'>> {
-  // Initialize variables with input data and include organizationId for action steps
-  const variables: ExecutionVariables = {
-    ...(typeof args.input === 'object' && args.input !== null
-      ? args.input
-      : {}),
-    organizationId: args.organizationId,
-  };
-
-  // Generate workflowSlug from workflow name using snake_case
-  // This creates a stable identifier for tracking processed entities
-  const workflowSlug = args.workflowName
-    ? snakeCase(args.workflowName)
-    : undefined;
-
-  debugLog('createExecution Creating execution', {
-    workflowName: args.workflowName,
-    workflowSlug,
-    organizationId: args.organizationId,
-  });
-
-  // Initialize with empty variables; they will be set via actions using storage-backed serialization
-  const serialized = JSON.stringify({});
-
-  return await ctx.db.insert('wfExecutions', {
-    organizationId: args.organizationId,
-    wfDefinitionId: args.wfDefinitionId,
-    status: 'running',
-    currentStepSlug: '',
-    startedAt: Date.now(),
-    updatedAt: Date.now(),
-    variables: serialized,
-    // No variablesStorageId at creation time (large payloads should be set from an action later)
-    input: args.input,
-    triggeredBy: args.triggeredBy,
-    triggerData: args.triggerData,
-    // Store potentially deeply nested configs as JSON strings to avoid Convex nesting limits
-    workflowConfig: args.workflowConfig
-      ? JSON.stringify(args.workflowConfig)
-      : JSON.stringify({}),
-    stepsConfig: args.stepsConfig
-      ? JSON.stringify(args.stepsConfig)
-      : JSON.stringify({}),
-    workflowSlug,
-  });
-}
diff --git a/services/platform/convex/model/wf_executions/index.ts b/services/platform/convex/model/wf_executions/index.ts
index db5cc5ca4c..d73b88b061 100644
--- a/services/platform/convex/model/wf_executions/index.ts
+++ b/services/platform/convex/model/wf_executions/index.ts
@@ -7,7 +7,6 @@
 export * from './types';
 
 // Export business logic functions
-export { createExecution } from './create_execution';
 export { getExecution } from './get_execution';
 export { getRawExecution } from './get_raw_execution';
 export { listExecutions } from './list_executions';
diff --git a/services/platform/convex/model/wf_executions/types.ts b/services/platform/convex/model/wf_executions/types.ts
index aa9db6e2b6..90f9706e52 100644
--- a/services/platform/convex/model/wf_executions/types.ts
+++ b/services/platform/convex/model/wf_executions/types.ts
@@ -23,17 +23,6 @@ export interface DeserializedWorkflowExecution
   variables: ExecutionVariables;
 }
 
-export interface CreateExecutionArgs {
-  organizationId: string;
-  wfDefinitionId: Doc<'wfDefinitions'>['_id'];
-  input?: unknown;
-  triggeredBy: string;
-  triggerData?: unknown;
-  workflowConfig?: unknown;
-  stepsConfig?: Record<string, unknown>;
-  workflowName?: string;
-}
-
 export interface UpdateExecutionStatusArgs {
   executionId: Doc<'wfExecutions'>['_id'];
   status: string;
@@ -102,17 +91,6 @@ export interface ListExecutionsArgs {
 // Convex Validators
 // =============================================================================
 
-export const createExecutionArgsValidator = {
-  organizationId: v.string(),
-  wfDefinitionId: v.id('wfDefinitions'),
-  input: v.optional(v.any()),
-  triggeredBy: v.string(),
-  triggerData: v.optional(v.any()),
-  workflowConfig: v.optional(v.any()),
-  stepsConfig: v.optional(v.record(v.string(), v.any())),
-  workflowName: v.optional(v.string()),
-};
-
 export const updateExecutionStatusArgsValidator = {
   executionId: v.id('wfExecutions'),
   status: v.string(),
diff --git a/services/platform/convex/model/workflow_processing_records/find_product_recommendation_by_status.ts b/services/platform/convex/model/workflow_processing_records/find_product_recommendation_by_status.ts
index 588a5b4571..26984d03d8 100644
--- a/services/platform/convex/model/workflow_processing_records/find_product_recommendation_by_status.ts
+++ b/services/platform/convex/model/workflow_processing_records/find_product_recommendation_by_status.ts
@@ -10,7 +10,7 @@ import { findUnprocessedWithCustomQuery } from './helpers/find_unprocessed_with_
 
 export interface FindProductRecommendationByStatusArgs {
   organizationId: string;
-  workflowId: string;
+  wfDefinitionId: string;
   backoffHours: number; // Number of hours to look back for processing records
   status: 'pending' | 'approved' | 'rejected';
 }
@@ -35,7 +35,7 @@ export async function findProductRecommendationByStatus(
   ctx: QueryCtx,
   args: FindProductRecommendationByStatusArgs,
 ): Promise<FindProductRecommendationByStatusResult> {
-  const { organizationId, workflowId, backoffHours, status } = args;
+  const { organizationId, wfDefinitionId, backoffHours, status } = args;
 
   // Calculate cutoff timestamp from backoffHours
   const cutoffDate = new Date();
@@ -45,7 +45,7 @@ export async function findProductRecommendationByStatus(
   const result = await findUnprocessedWithCustomQuery<Doc<'approvals'>>(ctx, {
     organizationId,
     tableName: 'approvals',
-    workflowId,
+    wfDefinitionId,
     cutoffTimestamp,
 
     // Build query with the specified status
@@ -78,4 +78,3 @@ export async function findProductRecommendationByStatus(
     count: result.count,
   };
 }
-
diff --git a/services/platform/convex/model/workflow_processing_records/find_unprocessed.ts b/services/platform/convex/model/workflow_processing_records/find_unprocessed.ts
index 46ca4d12b9..41d709d988 100644
--- a/services/platform/convex/model/workflow_processing_records/find_unprocessed.ts
+++ b/services/platform/convex/model/workflow_processing_records/find_unprocessed.ts
@@ -36,7 +36,7 @@ import { findUnprocessedWithCustomQuery } from './helpers/find_unprocessed_with_
 export interface FindUnprocessedArgs {
   organizationId: string;
   tableName: TableName;
-  workflowId: string;
+  wfDefinitionId: string;
   backoffHours: number; // Number of hours to look back for processing records
   limit?: number;
 }
@@ -56,7 +56,8 @@ export async function findUnprocessed(
   ctx: QueryCtx,
   args: FindUnprocessedArgs,
 ): Promise<FindUnprocessedResult> {
-  const { organizationId, tableName, workflowId, backoffHours, limit } = args;
+  const { organizationId, tableName, wfDefinitionId, backoffHours, limit } =
+    args;
 
   // Calculate cutoff timestamp from backoffHours
   const cutoffDate = new Date();
@@ -67,7 +68,7 @@ export async function findUnprocessed(
   const result = await findUnprocessedWithCustomQuery(ctx, {
     organizationId,
     tableName,
-    workflowId,
+    wfDefinitionId,
     cutoffTimestamp,
     limit,
 
diff --git a/services/platform/convex/model/workflow_processing_records/find_unprocessed_open_conversation.ts b/services/platform/convex/model/workflow_processing_records/find_unprocessed_open_conversation.ts
index 3f4abdebbb..50d35b6e4f 100644
--- a/services/platform/convex/model/workflow_processing_records/find_unprocessed_open_conversation.ts
+++ b/services/platform/convex/model/workflow_processing_records/find_unprocessed_open_conversation.ts
@@ -11,7 +11,7 @@ import { getLatestConversationMessage } from './helpers/get_latest_conversation_
 
 export interface FindUnprocessedOpenConversationArgs {
   organizationId: string;
-  workflowId: string;
+  wfDefinitionId: string;
   backoffHours: number; // Number of hours to look back for processing records
 }
 
@@ -38,7 +38,7 @@ export async function findUnprocessedOpenConversation(
   ctx: QueryCtx,
   args: FindUnprocessedOpenConversationArgs,
 ): Promise<FindUnprocessedOpenConversationResult> {
-  const { organizationId, workflowId, backoffHours } = args;
+  const { organizationId, wfDefinitionId, backoffHours } = args;
 
   // Calculate cutoff timestamp from backoffHours
   const cutoffDate = new Date();
@@ -50,7 +50,7 @@ export async function findUnprocessedOpenConversation(
     {
       organizationId,
       tableName: 'conversations',
-      workflowId,
+      wfDefinitionId,
       cutoffTimestamp,
 
       // Hook 1: Build your custom query with the right index
diff --git a/services/platform/convex/model/workflow_processing_records/helpers/find_unprocessed_with_custom_query.ts b/services/platform/convex/model/workflow_processing_records/helpers/find_unprocessed_with_custom_query.ts
index 0196d9cec6..2fe14c5218 100644
--- a/services/platform/convex/model/workflow_processing_records/helpers/find_unprocessed_with_custom_query.ts
+++ b/services/platform/convex/model/workflow_processing_records/helpers/find_unprocessed_with_custom_query.ts
@@ -17,7 +17,7 @@
  * const result = await findUnprocessedWithCustomQuery(ctx, {
  *   organizationId,
  *   tableName: 'conversations',
- *   workflowId,
+ *   wfDefinitionId,
  *   cutoffTimestamp,
  *   limit: 10,
  *   buildQuery: (resumeFrom) => {
@@ -65,7 +65,7 @@ export async function findUnprocessedWithCustomQuery<T = unknown>(
   ctx: QueryCtx,
   args: FindUnprocessedWithCustomQueryArgs<T>,
 ): Promise<FindUnprocessedWithCustomQueryResult<T>> {
-  const { organizationId, tableName, workflowId } = args;
+  const { organizationId, tableName, wfDefinitionId } = args;
   const limitVal = args.limit ?? 1;
 
   if (limitVal < 1 || limitVal > 10) {
@@ -78,7 +78,7 @@ export async function findUnprocessedWithCustomQuery<T = unknown>(
   const resumeFrom = await getLatestProcessedCreationTime(ctx, {
     organizationId,
     tableName,
-    workflowId,
+    wfDefinitionId,
   });
 
   // First, try starting from the latest processed creation time (resumeFrom)
diff --git a/services/platform/convex/model/workflow_processing_records/helpers/get_latest_processed_creation_time.ts b/services/platform/convex/model/workflow_processing_records/helpers/get_latest_processed_creation_time.ts
index 3c61f1a198..bb241b29a3 100644
--- a/services/platform/convex/model/workflow_processing_records/helpers/get_latest_processed_creation_time.ts
+++ b/services/platform/convex/model/workflow_processing_records/helpers/get_latest_processed_creation_time.ts
@@ -1,5 +1,5 @@
 /**
- * Get the _creationTime of the latest processed document for a workflow.
+ * Get the _creationTime of the latest processed record for a workflow.
  *
  * This is useful for resume optimization - you can start your query from this point
  * instead of scanning from the beginning.
@@ -10,7 +10,7 @@
  * const resumeFrom = await getLatestProcessedCreationTime(ctx, {
  *   organizationId,
  *   tableName: 'conversations',
- *   workflowId
+ *   wfDefinitionId
  * });
  *
  * // Build query with resume point
@@ -35,26 +35,26 @@ import { TableName } from '../types';
 export interface GetLatestProcessedCreationTimeArgs {
   organizationId: string;
   tableName: TableName;
-  workflowId: string;
+  wfDefinitionId: string;
 }
 
 export async function getLatestProcessedCreationTime(
   ctx: QueryCtx,
   args: GetLatestProcessedCreationTimeArgs,
 ): Promise<number | null> {
-  const { organizationId, tableName, workflowId } = args;
+  const { organizationId, tableName, wfDefinitionId } = args;
 
-  // Get the latest processed document for this workflow+table
+  // Get the latest processed record for this workflow+table
   const latestProcessed = await ctx.db
     .query('workflowProcessingRecords')
-    .withIndex('by_org_table_workflow_creationTime', (q) =>
+    .withIndex('by_org_table_wfDefinition_creationTime', (q) =>
       q
         .eq('organizationId', organizationId)
         .eq('tableName', tableName)
-        .eq('workflowId', workflowId),
+        .eq('wfDefinitionId', wfDefinitionId),
     )
     .order('desc')
     .first();
 
-  return latestProcessed?.documentCreationTime ?? null;
+  return latestProcessed?.recordCreationTime ?? null;
 }
diff --git a/services/platform/convex/model/workflow_processing_records/helpers/is_document_processed.ts b/services/platform/convex/model/workflow_processing_records/helpers/is_document_processed.ts
index 255afa8047..36faefa903 100644
--- a/services/platform/convex/model/workflow_processing_records/helpers/is_document_processed.ts
+++ b/services/platform/convex/model/workflow_processing_records/helpers/is_document_processed.ts
@@ -1,8 +1,8 @@
 /**
- * Check if a document has been processed by a workflow since the cutoff timestamp.
+ * Check if a record has been processed by a workflow since the cutoff timestamp.
  *
  * This helper allows you to write custom index queries and then check processing status
- * for individual documents during iteration.
+ * for individual records during iteration.
  *
  * @example
  * ```typescript
@@ -14,15 +14,15 @@
  *   )
  * ) {
  *   // Check if processed
- *   const isProcessed = await isDocumentProcessed(ctx, {
+ *   const isProcessed = await isRecordProcessed(ctx, {
  *     tableName: 'conversations',
- *     documentId: String(conv._id),
- *     workflowId,
+ *     recordId: String(conv._id),
+ *     wfDefinitionId,
  *     cutoffTimestamp
  *   });
  *
  *   if (!isProcessed) {
- *     // Process this document
+ *     // Process this record
  *   }
  * }
  * ```
@@ -31,33 +31,33 @@
 import { QueryCtx } from '../../../_generated/server';
 import { TableName } from '../types';
 
-export interface IsDocumentProcessedArgs {
+export interface IsRecordProcessedArgs {
   tableName: TableName;
-  documentId: string;
-  workflowId: string;
+  recordId: string;
+  wfDefinitionId: string;
   cutoffTimestamp: string; // ISO date string
 }
 
-export async function isDocumentProcessed(
+export async function isRecordProcessed(
   ctx: QueryCtx,
-  args: IsDocumentProcessedArgs,
+  args: IsRecordProcessedArgs,
 ): Promise<boolean> {
-  const { tableName, documentId, workflowId, cutoffTimestamp } = args;
+  const { tableName, recordId, wfDefinitionId, cutoffTimestamp } = args;
 
   // Convert cutoffTimestamp to milliseconds
   const cutoffMs = new Date(cutoffTimestamp).getTime();
 
-  // Check if this document has been processed since the cutoff
+  // Check if this record has been processed since the cutoff
   const processedRecord = await ctx.db
     .query('workflowProcessingRecords')
-    .withIndex('by_document', (q) =>
+    .withIndex('by_record', (q) =>
       q
         .eq('tableName', tableName)
-        .eq('documentId', documentId)
-        .eq('workflowId', workflowId),
+        .eq('recordId', recordId)
+        .eq('wfDefinitionId', wfDefinitionId),
     )
     .first();
 
-  // Document is processed if a record exists and was processed after cutoff
+  // Record is processed if a record exists and was processed after cutoff
   return processedRecord !== null && processedRecord.processedAt >= cutoffMs;
 }
diff --git a/services/platform/convex/model/workflow_processing_records/helpers/run_query.ts b/services/platform/convex/model/workflow_processing_records/helpers/run_query.ts
index 416d383107..b1c8e7d93c 100644
--- a/services/platform/convex/model/workflow_processing_records/helpers/run_query.ts
+++ b/services/platform/convex/model/workflow_processing_records/helpers/run_query.ts
@@ -1,15 +1,15 @@
 import { QueryCtx } from '../../../_generated/server';
 import { FindUnprocessedWithCustomQueryArgs } from '../types';
-import { isDocumentProcessed } from './is_document_processed';
+import { isRecordProcessed } from './is_document_processed';
 
 /**
  * Shared helper to run a workflow-processing query starting from a given
- * resume point and return matching documents.
+ * resume point and return matching records.
  *
  * This encapsulates the common logic of:
  * - Calling the caller-provided `buildQuery(startFrom)`
  * - Iterating candidates in index order
- * - Skipping already-processed documents (respecting `cutoffTimestamp`)
+ * - Skipping already-processed records (respecting `cutoffTimestamp`)
  * - Applying the optional `additionalFilter`
  */
 export async function runQuery<T = unknown>(
@@ -20,7 +20,7 @@ export async function runQuery<T = unknown>(
 ): Promise<T[]> {
   const {
     tableName,
-    workflowId,
+    wfDefinitionId,
     cutoffTimestamp,
     buildQuery,
     additionalFilter,
@@ -32,10 +32,10 @@ export async function runQuery<T = unknown>(
   for await (const doc of candidateIter) {
     const docId = String((doc as any)._id);
 
-    const processed = await isDocumentProcessed(ctx, {
+    const processed = await isRecordProcessed(ctx, {
       tableName,
-      documentId: docId,
-      workflowId,
+      recordId: docId,
+      wfDefinitionId,
       cutoffTimestamp,
     });
 
diff --git a/services/platform/convex/model/workflow_processing_records/index.ts b/services/platform/convex/model/workflow_processing_records/index.ts
index 32761385c0..e261a9c9c9 100644
--- a/services/platform/convex/model/workflow_processing_records/index.ts
+++ b/services/platform/convex/model/workflow_processing_records/index.ts
@@ -35,8 +35,8 @@ export type {
 } from './find_product_recommendation_by_status';
 
 // Helper functions for custom queries
-export { isDocumentProcessed } from './helpers/is_document_processed';
-export type { IsDocumentProcessedArgs } from './helpers/is_document_processed';
+export { isRecordProcessed } from './helpers/is_document_processed';
+export type { IsRecordProcessedArgs } from './helpers/is_document_processed';
 
 export { getLatestProcessedCreationTime } from './helpers/get_latest_processed_creation_time';
 export type { GetLatestProcessedCreationTimeArgs } from './helpers/get_latest_processed_creation_time';
diff --git a/services/platform/convex/model/workflow_processing_records/record_processed.ts b/services/platform/convex/model/workflow_processing_records/record_processed.ts
index 6a6a2fbacb..279f9a7dbb 100644
--- a/services/platform/convex/model/workflow_processing_records/record_processed.ts
+++ b/services/platform/convex/model/workflow_processing_records/record_processed.ts
@@ -10,9 +10,9 @@ import { TableName } from './types';
 export interface RecordProcessedArgs {
   organizationId: string;
   tableName: TableName;
-  documentId: string;
-  workflowId: string;
-  documentCreationTime: number;
+  recordId: string;
+  wfDefinitionId: string;
+  recordCreationTime: number;
   metadata?: unknown;
 }
 
@@ -23,20 +23,20 @@ export async function recordProcessed(
   const {
     organizationId,
     tableName,
-    documentId,
-    workflowId,
-    documentCreationTime,
+    recordId,
+    wfDefinitionId,
+    recordCreationTime,
     metadata,
   } = args;
 
-  // Check if this document has already been recorded for this workflow
+  // Check if this record has already been recorded for this workflow
   const existing = await ctx.db
     .query('workflowProcessingRecords')
-    .withIndex('by_document', (q) =>
+    .withIndex('by_record', (q) =>
       q
         .eq('tableName', tableName)
-        .eq('documentId', documentId)
-        .eq('workflowId', workflowId),
+        .eq('recordId', recordId)
+        .eq('wfDefinitionId', wfDefinitionId),
     )
     .first();
 
@@ -53,9 +53,9 @@ export async function recordProcessed(
   return await ctx.db.insert('workflowProcessingRecords', {
     organizationId,
     tableName,
-    documentId,
-    workflowId,
-    documentCreationTime,
+    recordId,
+    wfDefinitionId,
+    recordCreationTime,
     processedAt: Date.now(),
     metadata,
   });
diff --git a/services/platform/convex/model/workflow_processing_records/types.ts b/services/platform/convex/model/workflow_processing_records/types.ts
index 92fc4bd645..ceb8145399 100644
--- a/services/platform/convex/model/workflow_processing_records/types.ts
+++ b/services/platform/convex/model/workflow_processing_records/types.ts
@@ -21,7 +21,7 @@ export type TableName =
 export interface FindUnprocessedWithCustomQueryArgs<T = unknown> {
   organizationId: string;
   tableName: TableName;
-  workflowId: string;
+  wfDefinitionId: string;
   cutoffTimestamp: string;
   limit?: number;
 
diff --git a/services/platform/convex/predefined_workflows/conversation_auto_reply.ts b/services/platform/convex/predefined_workflows/conversation_auto_reply.ts
index 720f34d8a4..c04e9bf1cc 100644
--- a/services/platform/convex/predefined_workflows/conversation_auto_reply.ts
+++ b/services/platform/convex/predefined_workflows/conversation_auto_reply.ts
@@ -66,7 +66,7 @@ export const conversationAutoReplyWorkflow = {
         parameters: {
           operation: 'find_unprocessed_open_conversation',
           organizationId: '{{organizationId}}',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -439,9 +439,9 @@ Task: As John, generate a warm and professional reply in markdown format that ad
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'conversations',
-          documentId: '{{currentConversationId}}',
-          workflowId: '{{workflowId}}',
-          documentCreationTime: '{{currentConversationCreationTime}}',
+          recordId: '{{currentConversationId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
+          recordCreationTime: '{{currentConversationCreationTime}}',
           metadata: {
             needsReply: '{{steps.check_needs_reply.output.data.needs_reply}}',
             urgency: '{{steps.check_needs_reply.output.data.urgency}}',
diff --git a/services/platform/convex/predefined_workflows/customer_rag_sync.ts b/services/platform/convex/predefined_workflows/customer_rag_sync.ts
index 2ed7705e28..ad7f69a51b 100644
--- a/services/platform/convex/predefined_workflows/customer_rag_sync.ts
+++ b/services/platform/convex/predefined_workflows/customer_rag_sync.ts
@@ -53,7 +53,7 @@ export const customerRagSyncWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -114,11 +114,11 @@ export const customerRagSyncWorkflow = {
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          documentId:
+          recordId:
             '{{steps.find_unprocessed_customer.output.data.documents[0]._id}}',
-          documentCreationTime:
+          recordCreationTime:
             '{{steps.find_unprocessed_customer.output.data.documents[0]._creationTime}}',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/predefined_workflows/document_rag_sync.ts b/services/platform/convex/predefined_workflows/document_rag_sync.ts
index 86645a0217..f37083e712 100644
--- a/services/platform/convex/predefined_workflows/document_rag_sync.ts
+++ b/services/platform/convex/predefined_workflows/document_rag_sync.ts
@@ -52,7 +52,7 @@ export const documentRagSyncWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'documents',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -130,11 +130,11 @@ export const documentRagSyncWorkflow = {
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'documents',
-          documentId:
+          recordId:
             '{{steps.find_unprocessed_document.output.data.documents[0]._id}}',
-          documentCreationTime:
+          recordCreationTime:
             '{{steps.find_unprocessed_document.output.data.documents[0]._creationTime}}',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/predefined_workflows/general_customer_status_assessment.ts b/services/platform/convex/predefined_workflows/general_customer_status_assessment.ts
index cc8620d939..3e77ab0f31 100644
--- a/services/platform/convex/predefined_workflows/general_customer_status_assessment.ts
+++ b/services/platform/convex/predefined_workflows/general_customer_status_assessment.ts
@@ -35,7 +35,7 @@ export const generalCustomerStatusAssessmentWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -203,9 +203,9 @@ Return ONLY JSON in the exact shape described in the system prompt.`,
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
-          documentId: '{{currentCustomerId}}',
-          documentCreationTime: '{{currentCustomer._creationTime}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
+          recordId: '{{currentCustomerId}}',
+          recordCreationTime: '{{currentCustomer._creationTime}}',
           metadata: {
             processedAt: '{{now}}',
             statusUpdated: true,
diff --git a/services/platform/convex/predefined_workflows/general_product_recommendation.ts b/services/platform/convex/predefined_workflows/general_product_recommendation.ts
index 5ac0fdfc3b..15a03185ae 100644
--- a/services/platform/convex/predefined_workflows/general_product_recommendation.ts
+++ b/services/platform/convex/predefined_workflows/general_product_recommendation.ts
@@ -37,7 +37,7 @@ export const generalProductRecommendationWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -251,7 +251,7 @@ Example of a VALID response (do NOT explain it, just return JSON like this):
               '{{steps.hydrate_recommendations.output.data.recommendations}}',
             summary: '{{steps.generate_recommendations.output.data.summary}}',
             generatedAt: '{{now}}',
-            workflowId: '{{workflowId}}',
+            workflowId: '{{rootWfDefinitionId}}',
           },
         },
       },
@@ -268,9 +268,9 @@ Example of a VALID response (do NOT explain it, just return JSON like this):
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
-          documentId: '{{currentCustomerId}}',
-          documentCreationTime: '{{currentCustomer._creationTime}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
+          recordId: '{{currentCustomerId}}',
+          recordCreationTime: '{{currentCustomer._creationTime}}',
           metadata: {
             recommendationsGenerated:
               '{{steps.hydrate_recommendations.output.data.recommendations|length}}',
diff --git a/services/platform/convex/predefined_workflows/loopi_customer_status_assessment.ts b/services/platform/convex/predefined_workflows/loopi_customer_status_assessment.ts
index 987db6891e..306d0e99fe 100644
--- a/services/platform/convex/predefined_workflows/loopi_customer_status_assessment.ts
+++ b/services/platform/convex/predefined_workflows/loopi_customer_status_assessment.ts
@@ -78,7 +78,7 @@ export const loopiCustomerStatusAssessmentWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -219,9 +219,9 @@ Analyze the subscription data and provide your determination strictly as JSON wi
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
-          documentId: '{{currentCustomerId}}',
-          documentCreationTime: '{{currentCustomer._creationTime}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
+          recordId: '{{currentCustomerId}}',
+          recordCreationTime: '{{currentCustomer._creationTime}}',
           metadata: {
             processedAt: '{{now}}',
             statusUpdated: true,
diff --git a/services/platform/convex/predefined_workflows/loopi_product_recommendation.ts b/services/platform/convex/predefined_workflows/loopi_product_recommendation.ts
index 4878e8cfe6..d2ea9df559 100644
--- a/services/platform/convex/predefined_workflows/loopi_product_recommendation.ts
+++ b/services/platform/convex/predefined_workflows/loopi_product_recommendation.ts
@@ -75,7 +75,7 @@ export const loopiProductRecommendationWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -453,7 +453,7 @@ DO NOT use the same confidence score for all recommendations.`,
               '{{steps.hydrate_recommendations.output.data.recommendations}}',
             summary: '{{steps.generate_recommendations.output.data.summary}}',
             generatedAt: '{{now}}',
-            workflowId: '{{workflowId}}',
+            workflowId: '{{rootWfDefinitionId}}',
           },
         },
       },
@@ -474,9 +474,9 @@ DO NOT use the same confidence score for all recommendations.`,
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'customers',
-          workflowId: '{{workflowId}}',
-          documentId: '{{currentCustomerId}}',
-          documentCreationTime: '{{currentCustomer._creationTime}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
+          recordId: '{{currentCustomerId}}',
+          recordCreationTime: '{{currentCustomer._creationTime}}',
           metadata: {
             recommendationsGenerated:
               '{{steps.hydrate_recommendations.output.data.recommendations|length}}',
diff --git a/services/platform/convex/predefined_workflows/onedrive_sync.ts b/services/platform/convex/predefined_workflows/onedrive_sync.ts
index c4c1e7cc23..1542bae35d 100644
--- a/services/platform/convex/predefined_workflows/onedrive_sync.ts
+++ b/services/platform/convex/predefined_workflows/onedrive_sync.ts
@@ -62,7 +62,7 @@ export const onedriveSyncWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'onedriveSyncConfigs',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -334,10 +334,10 @@ export const onedriveSyncWorkflow = {
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'onedriveSyncConfigs',
-          documentId: '{{steps.find_sync_config.output.data.documents[0]._id}}',
-          documentCreationTime:
+          recordId: '{{steps.find_sync_config.output.data.documents[0]._id}}',
+          recordCreationTime:
             '{{steps.find_sync_config.output.data.documents[0]._creationTime}}',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/predefined_workflows/product_rag_sync.ts b/services/platform/convex/predefined_workflows/product_rag_sync.ts
index a5b262ef95..f24be34229 100644
--- a/services/platform/convex/predefined_workflows/product_rag_sync.ts
+++ b/services/platform/convex/predefined_workflows/product_rag_sync.ts
@@ -53,7 +53,7 @@ export const productRagSyncWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'products',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -114,11 +114,11 @@ export const productRagSyncWorkflow = {
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'products',
-          documentId:
+          recordId:
             '{{steps.find_unprocessed_product.output.data.documents[0]._id}}',
-          documentCreationTime:
+          recordCreationTime:
             '{{steps.find_unprocessed_product.output.data.documents[0]._creationTime}}',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/predefined_workflows/product_recommendation_email.ts b/services/platform/convex/predefined_workflows/product_recommendation_email.ts
index e2a9adaf6e..74ed008ad2 100644
--- a/services/platform/convex/predefined_workflows/product_recommendation_email.ts
+++ b/services/platform/convex/predefined_workflows/product_recommendation_email.ts
@@ -81,7 +81,7 @@ export const productRecommendationEmailWorkflow = {
         parameters: {
           operation: 'find_product_recommendation_by_status',
           organizationId: '{{organizationId}}',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
           status: 'approved',
         },
@@ -320,9 +320,9 @@ Return only the JSON object with "subject", "body", and "preview".`,
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'approvals',
-          workflowId: '{{workflowId}}',
-          documentId: '{{currentApprovalId}}',
-          documentCreationTime: '{{currentApproval._creationTime}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
+          recordId: '{{currentApprovalId}}',
+          recordCreationTime: '{{currentApproval._creationTime}}',
           metadata: {
             emailGenerated: true,
             conversationId:
diff --git a/services/platform/convex/predefined_workflows/product_relationship_analysis.ts b/services/platform/convex/predefined_workflows/product_relationship_analysis.ts
index 60d03f68e1..2afddaea01 100644
--- a/services/platform/convex/predefined_workflows/product_relationship_analysis.ts
+++ b/services/platform/convex/predefined_workflows/product_relationship_analysis.ts
@@ -68,7 +68,7 @@ export const productRelationshipAnalysisWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'products',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -474,9 +474,9 @@ BIDIRECTIONAL RELATIONSHIPS:
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'products',
-          workflowId: '{{workflowId}}',
-          documentId: '{{sourceProductId}}',
-          documentCreationTime: '{{sourceProduct._creationTime}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
+          recordId: '{{sourceProductId}}',
+          recordCreationTime: '{{sourceProduct._creationTime}}',
           metadata: {
             relationshipsFound:
               '{{steps.analyze_product_relationships.output.data.relationships|length}}',
diff --git a/services/platform/convex/predefined_workflows/website_pages_rag_sync.ts b/services/platform/convex/predefined_workflows/website_pages_rag_sync.ts
index e36dfec568..a9de6cdd2d 100644
--- a/services/platform/convex/predefined_workflows/website_pages_rag_sync.ts
+++ b/services/platform/convex/predefined_workflows/website_pages_rag_sync.ts
@@ -47,7 +47,7 @@ export const websitePagesRagSyncWorkflow = {
           operation: 'find_unprocessed',
           organizationId: '{{organizationId}}',
           tableName: 'websitePages',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
           backoffHours: '{{backoffHours}}',
         },
       },
@@ -104,11 +104,11 @@ export const websitePagesRagSyncWorkflow = {
           operation: 'record_processed',
           organizationId: '{{organizationId}}',
           tableName: 'websitePages',
-          documentId:
+          recordId:
             '{{steps.find_unprocessed_page.output.data.documents[0]._id}}',
-          documentCreationTime:
+          recordCreationTime:
             '{{steps.find_unprocessed_page.output.data.documents[0]._creationTime}}',
-          workflowId: '{{workflowId}}',
+          wfDefinitionId: '{{rootWfDefinitionId}}',
         },
       },
       nextSteps: {
diff --git a/services/platform/convex/schema.ts b/services/platform/convex/schema.ts
index 622cf9bc8c..25b09abc95 100644
--- a/services/platform/convex/schema.ts
+++ b/services/platform/convex/schema.ts
@@ -640,6 +640,7 @@ export default defineSchema({
   wfExecutions: defineTable({
     organizationId: v.string(), // Better Auth organization ID
     wfDefinitionId: v.union(v.id('wfDefinitions'), v.string(), v.null()), // references workflow template, inline identifier, or null for inline workflows
+    rootWfDefinitionId: v.optional(v.id('wfDefinitions')), // Root version of the workflow family (from wfDefinitions.rootVersionId)
 
     // Version tracking (for audit and debugging)
     workflowSlug: v.optional(v.string()), // Stable workflow identifier (snake_case of name) for entity tracking
@@ -798,35 +799,35 @@ export default defineSchema({
   workflowProcessingRecords: defineTable({
     organizationId: v.string(), // Better Auth organization ID
     tableName: v.string(), // 'customers' | 'products' | 'subscriptions' | etc.
-    documentId: v.string(), // The _id of the processed document (stored as string for flexibility)
-    workflowId: v.string(), // Workflow identifier (workflowSlug or workflowId)
+    recordId: v.string(), // The _id of the processed record (stored as string for flexibility)
+    wfDefinitionId: v.string(), // Workflow definition identifier (workflowSlug or wfDefinitionId)
 
-    // Document metadata at time of processing
-    documentCreationTime: v.number(), // _creationTime of the processed document
+    // Record metadata at time of processing
+    recordCreationTime: v.number(), // _creationTime of the processed record
 
     // Processing metadata
-    processedAt: v.number(), // When this document was processed
+    processedAt: v.number(), // When this record was processed
 
     metadata: v.optional(v.any()),
   })
-    .index('by_org_table_workflow', [
+    .index('by_org_table_wfDefinition', [
       'organizationId',
       'tableName',
-      'workflowId',
+      'wfDefinitionId',
     ])
-    .index('by_org_table_workflow_creationTime', [
+    .index('by_org_table_wfDefinition_creationTime', [
       'organizationId',
       'tableName',
-      'workflowId',
-      'documentCreationTime',
+      'wfDefinitionId',
+      'recordCreationTime',
     ])
-    .index('by_org_table_workflow_processedAt', [
+    .index('by_org_table_wfDefinition_processedAt', [
       'organizationId',
       'tableName',
-      'workflowId',
+      'wfDefinitionId',
       'processedAt',
     ])
-    .index('by_document', ['tableName', 'documentId', 'workflowId']),
+    .index('by_record', ['tableName', 'recordId', 'wfDefinitionId']),
 
   // Message Metadata (for tracking LLM usage, tokens, model info)
   messageMetadata: defineTable({
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status.ts
index 983110466a..6b44a80852 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_product_recommendation_by_status.ts
@@ -11,7 +11,7 @@ export async function findProductRecommendationByStatus(
   ctx: ActionCtx,
   params: {
     organizationId: string;
-    workflowId: string;
+    wfDefinitionId: string;
     backoffHours: number;
     status: 'pending' | 'approved' | 'rejected';
   },
@@ -21,7 +21,7 @@ export async function findProductRecommendationByStatus(
     internal.workflow_processing_records.findProductRecommendationByStatus,
     {
       organizationId: params.organizationId,
-      workflowId: params.workflowId,
+      wfDefinitionId: params.wfDefinitionId,
       backoffHours: params.backoffHours,
       status: params.status,
     },
@@ -32,4 +32,3 @@ export async function findProductRecommendationByStatus(
     count: result.count,
   };
 }
-
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed.ts
index bf34e5ca2c..bd0a795da2 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed.ts
@@ -8,7 +8,7 @@ export async function findUnprocessed(
   params: {
     organizationId: string;
     tableName: TableName;
-    workflowId: string;
+    wfDefinitionId: string;
     backoffHours: number;
   },
 ): Promise<FindUnprocessedResult> {
@@ -17,7 +17,7 @@ export async function findUnprocessed(
     {
       organizationId: params.organizationId,
       tableName: params.tableName,
-      workflowId: params.workflowId,
+      wfDefinitionId: params.wfDefinitionId,
       backoffHours: params.backoffHours,
     },
   );
@@ -27,4 +27,3 @@ export async function findUnprocessed(
     count: result.count,
   };
 }
-
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation.ts
index a7f609d795..2b98ee5551 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/find_unprocessed_open_conversation.ts
@@ -7,7 +7,7 @@ export async function findUnprocessedOpenConversation(
   ctx: ActionCtx,
   params: {
     organizationId: string;
-    workflowId: string;
+    wfDefinitionId: string;
     backoffHours: number;
   },
 ): Promise<FindUnprocessedResult> {
@@ -15,7 +15,7 @@ export async function findUnprocessedOpenConversation(
     internal.workflow_processing_records.findUnprocessedOpenConversation,
     {
       organizationId: params.organizationId,
-      workflowId: params.workflowId,
+      wfDefinitionId: params.wfDefinitionId,
       backoffHours: params.backoffHours,
     },
   );
@@ -25,4 +25,3 @@ export async function findUnprocessedOpenConversation(
     count: result.count,
   };
 }
-
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/helpers/record_processed.ts b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/record_processed.ts
index 36edd7ca47..b0712f6110 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/helpers/record_processed.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/helpers/record_processed.ts
@@ -8,29 +8,29 @@ export async function recordProcessed(
   params: {
     organizationId: string;
     tableName: TableName;
-    documentId: string;
-    workflowId: string;
-    documentCreationTime: number;
+    recordId: string;
+    wfDefinitionId: string;
+    recordCreationTime: number;
     metadata?: unknown;
   },
 ): Promise<RecordProcessedResult> {
-  const recordId: Id<'workflowProcessingRecords'> = await ctx.runMutation(
-    internal.workflow_processing_records.recordProcessed,
-    {
-      organizationId: params.organizationId,
-      tableName: params.tableName,
-      documentId: params.documentId,
-      workflowId: params.workflowId,
-      documentCreationTime: params.documentCreationTime,
-      metadata: params.metadata,
-    },
-  );
+  const processingRecordId: Id<'workflowProcessingRecords'> =
+    await ctx.runMutation(
+      internal.workflow_processing_records.recordProcessed,
+      {
+        organizationId: params.organizationId,
+        tableName: params.tableName,
+        recordId: params.recordId,
+        wfDefinitionId: params.wfDefinitionId,
+        recordCreationTime: params.recordCreationTime,
+        metadata: params.metadata,
+      },
+    );
 
   return {
     operation: 'record_processed',
-    recordId,
+    recordId: processingRecordId,
     success: true,
     timestamp: Date.now(),
   };
 }
-
diff --git a/services/platform/convex/workflow/actions/workflow_processing_records/workflow_processing_records_action.ts b/services/platform/convex/workflow/actions/workflow_processing_records/workflow_processing_records_action.ts
index ea178af0f7..9e79c29a0c 100644
--- a/services/platform/convex/workflow/actions/workflow_processing_records/workflow_processing_records_action.ts
+++ b/services/platform/convex/workflow/actions/workflow_processing_records/workflow_processing_records_action.ts
@@ -26,11 +26,11 @@ export const workflowProcessingRecordsAction: ActionDefinition<{
     | 'record_processed';
   organizationId: string;
   tableName?: TableName;
-  workflowId: string;
+  wfDefinitionId: string;
   backoffHours?: number;
   status?: 'pending' | 'approved' | 'rejected';
-  documentId?: string;
-  documentCreationTime?: number;
+  recordId?: string;
+  recordCreationTime?: number;
   metadata?: unknown;
 }> = {
   type: 'workflow_processing_records',
@@ -57,7 +57,7 @@ export const workflowProcessingRecordsAction: ActionDefinition<{
         v.literal('exampleMessages'),
       ),
     ),
-    workflowId: v.string(),
+    wfDefinitionId: v.string(),
     backoffHours: v.optional(v.number()),
     status: v.optional(
       v.union(
@@ -66,8 +66,8 @@ export const workflowProcessingRecordsAction: ActionDefinition<{
         v.literal('rejected'),
       ),
     ),
-    documentId: v.optional(v.string()),
-    documentCreationTime: v.optional(v.number()),
+    recordId: v.optional(v.string()),
+    recordCreationTime: v.optional(v.number()),
     metadata: v.optional(v.any()),
   }),
 
@@ -88,7 +88,7 @@ export const workflowProcessingRecordsAction: ActionDefinition<{
         return await findUnprocessed(ctx, {
           organizationId: params.organizationId,
           tableName: params.tableName,
-          workflowId: params.workflowId,
+          wfDefinitionId: params.wfDefinitionId,
           backoffHours: params.backoffHours,
         });
       }
@@ -102,7 +102,7 @@ export const workflowProcessingRecordsAction: ActionDefinition<{
 
         return await findUnprocessedOpenConversation(ctx, {
           organizationId: params.organizationId,
-          workflowId: params.workflowId,
+          wfDefinitionId: params.wfDefinitionId,
           backoffHours: params.backoffHours,
         });
       }
@@ -121,7 +121,7 @@ export const workflowProcessingRecordsAction: ActionDefinition<{
 
         return await findProductRecommendationByStatus(ctx, {
           organizationId: params.organizationId,
-          workflowId: params.workflowId,
+          wfDefinitionId: params.wfDefinitionId,
           backoffHours: params.backoffHours,
           status: params.status,
         });
@@ -133,23 +133,23 @@ export const workflowProcessingRecordsAction: ActionDefinition<{
             'record_processed operation requires tableName parameter',
           );
         }
-        if (!params.documentId) {
+        if (!params.recordId) {
           throw new Error(
-            'record_processed operation requires documentId parameter',
+            'record_processed operation requires recordId parameter',
           );
         }
-        if (params.documentCreationTime === undefined) {
+        if (params.recordCreationTime === undefined) {
           throw new Error(
-            'record_processed operation requires documentCreationTime parameter',
+            'record_processed operation requires recordCreationTime parameter',
           );
         }
 
         return await recordProcessed(ctx, {
           organizationId: params.organizationId,
           tableName: params.tableName,
-          documentId: params.documentId,
-          workflowId: params.workflowId,
-          documentCreationTime: params.documentCreationTime,
+          recordId: params.recordId,
+          wfDefinitionId: params.wfDefinitionId,
+          recordCreationTime: params.recordCreationTime,
           metadata: params.metadata,
         });
       }
diff --git a/services/platform/convex/workflow/helpers/engine/start_workflow_handler.ts b/services/platform/convex/workflow/helpers/engine/start_workflow_handler.ts
index b14f8821a1..753cb03852 100644
--- a/services/platform/convex/workflow/helpers/engine/start_workflow_handler.ts
+++ b/services/platform/convex/workflow/helpers/engine/start_workflow_handler.ts
@@ -25,9 +25,9 @@ export async function handleStartWorkflow(
   args: StartWorkflowArgs,
   workflowManager: WorkflowManager,
 ): Promise<Id<'wfExecutions'>> {
-  // Validate database workflow
-  const workflow = await ctx.db.get(args.wfDefinitionId);
-  if (!workflow) {
+  // Validate database workflow definition
+  const wfDefinition = await ctx.db.get(args.wfDefinitionId);
+  if (!wfDefinition) {
     throw new Error('Workflow definition not found');
   }
 
@@ -43,20 +43,25 @@ export async function handleStartWorkflow(
     throw new Error('No steps defined for workflow');
   }
 
-  const workflowName = workflow.name;
+  const workflowName = wfDefinition.name;
 
   // Generate workflowSlug from workflow name
   const workflowSlug = snakeCase(workflowName);
 
+  // Get rootWfDefinitionId: use wfDefinition's rootVersionId, or fall back to its own _id
+  const rootWfDefinitionId = wfDefinition.rootVersionId ?? wfDefinition._id;
+
   debugLog('startWorkflow Creating execution', {
     workflowName,
     workflowSlug,
+    rootWfDefinitionId,
   });
 
   // Pre-create execution record with pending status
   const executionId: Id<'wfExecutions'> = await ctx.db.insert('wfExecutions', {
     organizationId: args.organizationId,
     wfDefinitionId: args.wfDefinitionId,
+    rootWfDefinitionId,
     status: 'pending',
     currentStepSlug: '',
     input: args.input || {},
diff --git a/services/platform/convex/workflow/helpers/step_execution/initialize_execution_variables.ts b/services/platform/convex/workflow/helpers/step_execution/initialize_execution_variables.ts
index 911e088f86..d48fdf7e6b 100644
--- a/services/platform/convex/workflow/helpers/step_execution/initialize_execution_variables.ts
+++ b/services/platform/convex/workflow/helpers/step_execution/initialize_execution_variables.ts
@@ -21,12 +21,15 @@ export async function initializeExecutionVariables(
   args: InitializeVariablesArgs,
   workflowConfig: WorkflowConfig,
 ): Promise<Record<string, unknown>> {
-  // Determine workflowId: prefer wfDefinitionId, fallback to workflowSlug for inline workflows
-  const workflowId = execution.wfDefinitionId ?? execution.workflowSlug;
+  // Determine wfDefinitionId: prefer wfDefinitionId, fallback to workflowSlug for inline workflows
+  const wfDefinitionId = execution.wfDefinitionId ?? execution.workflowSlug;
+  // rootWfDefinitionId: root version of the workflow family (for tracking across versions)
+  const rootWfDefinitionId = execution.rootWfDefinitionId;
 
   let fullVariables: Record<string, unknown> = {
     organizationId: args.organizationId,
-    workflowId, // Auto-inject wfDefinitionId or workflowSlug as workflowId
+    wfDefinitionId, // Auto-inject wfDefinitionId or workflowSlug
+    rootWfDefinitionId, // Auto-inject root workflow definition ID
   };
 
   // Use execution variables as the base, or initialize if empty
@@ -34,7 +37,8 @@ export async function initializeExecutionVariables(
     fullVariables = {
       ...(execution.variables as Record<string, unknown>),
       organizationId: args.organizationId,
-      workflowId, // Auto-inject wfDefinitionId or workflowSlug as workflowId
+      wfDefinitionId, // Auto-inject wfDefinitionId or workflowSlug
+      rootWfDefinitionId, // Auto-inject root workflow definition ID
     };
   } else {
     // Initialize execution variables for the first time
@@ -42,7 +46,8 @@ export async function initializeExecutionVariables(
       ...((args.resumeVariables ?? args.initialInput) || {}),
       ...(workflowConfig?.config?.variables ?? {}),
       organizationId: args.organizationId,
-      workflowId, // Auto-inject wfDefinitionId or workflowSlug as workflowId
+      wfDefinitionId, // Auto-inject wfDefinitionId or workflowSlug
+      rootWfDefinitionId, // Auto-inject root workflow definition ID
     };
 
     // Handle secrets decryption for initial setup
diff --git a/services/platform/convex/workflow/helpers/step_execution/types.ts b/services/platform/convex/workflow/helpers/step_execution/types.ts
index 90000c1605..6382b76554 100644
--- a/services/platform/convex/workflow/helpers/step_execution/types.ts
+++ b/services/platform/convex/workflow/helpers/step_execution/types.ts
@@ -18,6 +18,7 @@ export interface StepDefinition {
 export interface ExecutionData {
   _id: Id<'wfExecutions'>;
   wfDefinitionId?: Id<'wfDefinitions'> | null;
+  rootWfDefinitionId?: Id<'wfDefinitions'>; // Root version of the workflow family
   stepsConfig?: Record<string, unknown>;
   workflowConfig?: WorkflowConfig;
   variables?: Record<string, unknown>;
diff --git a/services/platform/convex/workflow_processing_records.ts b/services/platform/convex/workflow_processing_records.ts
index a9db76b1fb..5405ab9183 100644
--- a/services/platform/convex/workflow_processing_records.ts
+++ b/services/platform/convex/workflow_processing_records.ts
@@ -29,22 +29,22 @@ import * as WorkflowProcessingRecordsModel from './model/workflow_processing_rec
 // =============================================================================
 
 /**
- * Find unprocessed documents in a table for a specific workflow.
+ * Find unprocessed records in a table for a specific workflow.
  *
  * Algorithm:
- * 1. Get the latest processed document (by documentCreationTime)
- * 2. Get the latest document in the target table (by _creationTime)
+ * 1. Get the latest processed record (by recordCreationTime)
+ * 2. Get the latest record in the target table (by _creationTime)
  * 3. If latest processed == latest in table OR no processing history exists:
- *    - Start from the earliest unprocessed document
+ *    - Start from the earliest unprocessed record
  * 4. Otherwise:
- *    - Continue from where we left off (documents with _creationTime > last processed)
+ *    - Continue from where we left off (records with _creationTime > last processed)
  *
  * This approach:
- * - Avoids scanning all documents
+ * - Avoids scanning all records
  * - Uses indexes efficiently
  * - Tracks processing progress per workflow per table
  * - Can resume from where it left off
- * - Always returns exactly one document (limit defaults to 1)
+ * - Always returns exactly one record (limit defaults to 1)
  */
 export const findUnprocessed = internalQuery({
   args: {
@@ -59,7 +59,7 @@ export const findUnprocessed = internalQuery({
       v.literal('websitePages'),
       v.literal('exampleMessages'),
     ),
-    workflowId: v.string(),
+    wfDefinitionId: v.string(),
     backoffHours: v.number(),
     limit: v.optional(v.number()),
   },
@@ -81,7 +81,7 @@ export const findUnprocessed = internalQuery({
 export const findUnprocessedOpenConversation = internalQuery({
   args: {
     organizationId: v.string(),
-    workflowId: v.string(),
+    wfDefinitionId: v.string(),
     backoffHours: v.number(),
   },
   returns: v.object({
@@ -105,7 +105,7 @@ export const findUnprocessedOpenConversation = internalQuery({
 export const findProductRecommendationByStatus = internalQuery({
   args: {
     organizationId: v.string(),
-    workflowId: v.string(),
+    wfDefinitionId: v.string(),
     backoffHours: v.number(),
     status: v.union(
       v.literal('pending'),
@@ -142,9 +142,9 @@ export const recordProcessed = internalMutation({
       v.literal('websitePages'),
       v.literal('exampleMessages'),
     ),
-    documentId: v.string(),
-    workflowId: v.string(),
-    documentCreationTime: v.number(),
+    recordId: v.string(),
+    wfDefinitionId: v.string(),
+    recordCreationTime: v.number(),
     metadata: v.optional(v.any()),
   },
   returns: v.id('workflowProcessingRecords'),

From e2378b42f8c80272b501c16f3318f7cecb43ee74 Mon Sep 17 00:00:00 2001
From: larryro <371767072@qq.com>
Date: Wed, 3 Dec 2025 18:22:47 +0800
Subject: [PATCH 3/3] fix(jexl): use JSON.stringify for objects/arrays in
 string transform

---
 services/platform/convex/lib/variables/jexl_instance.ts | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/services/platform/convex/lib/variables/jexl_instance.ts b/services/platform/convex/lib/variables/jexl_instance.ts
index ef786387a7..5043b09dc2 100644
--- a/services/platform/convex/lib/variables/jexl_instance.ts
+++ b/services/platform/convex/lib/variables/jexl_instance.ts
@@ -46,7 +46,13 @@ jexlInstance.addTransform('join', (arr: unknown[], separator = ',') => {
 });
 
 // Add custom transforms for type conversion
-jexlInstance.addTransform('string', (val: unknown) => toString(val));
+jexlInstance.addTransform('string', (val: unknown) => {
+  // For objects and arrays, use JSON.stringify to get proper string representation
+  if (val !== null && typeof val === 'object') {
+    return JSON.stringify(val);
+  }
+  return toString(val);
+});
 jexlInstance.addTransform('number', (val: unknown) => toNumber(val));
 jexlInstance.addTransform('boolean', (val: unknown) => Boolean(val));
 
