Skip to content

fix(evocrm): runtime patches bugs 20-27 for evo-ai-crm-community rc5#116

Open
dvlexp wants to merge 1 commit into
evolution-foundation:mainfrom
dvlexp:fix/evocrm-patches-aurora-messages-update
Open

fix(evocrm): runtime patches bugs 20-27 for evo-ai-crm-community rc5#116
dvlexp wants to merge 1 commit into
evolution-foundation:mainfrom
dvlexp:fix/evocrm-patches-aurora-messages-update

Conversation

@dvlexp

@dvlexp dvlexp commented Jul 1, 2026

Copy link
Copy Markdown

Summary

Adds scripts/evocrm-patches/ with runtime monkey-patches for known issues in evo-ai-crm-community:1.0.0-rc5. Patches are loaded at startup via Rails.application.config.to_prepare in rxp_patches.rb.

Bug 26 (critical) -- Aurora MESSAGES_UPDATE never progresses past sent

Root cause: Whatsapp::EvolutionHandlers::Helpers#raw_message_id prefers :messageId over :keyId. For Evolution API v2 Cloud API (WABA) inboxes, the messages.update event payload contains two fields:

Field Value Meaning
messageId cmqs7ozt705cepl01mlhe3z42 Internal Prisma DB ID of Evolution API (useless in CRM)
keyId wamid.HBgM... Actual wamid = source_id in CRM

With the original priority, find_message_by_source_id(messageId) always returns nil and the status update is silently discarded. Affects all WABA/Cloud API inboxes using Evolution API v2.

Fix: One-line change -- invert priority to :keyId || :messageId || dig(:key, :id).

Safe: for messages.upsert events, neither :keyId nor :messageId exist and the existing fallback @raw_message.dig(:key, :id) continues to work normally.

Bug 27 -- Filter lost when paginating conversations

Root cause: loadMoreConversations always calls GET /conversations?page=N without active filters, even when the initial load used POST /conversations/filter. Page 2+ returns unfiltered results.

Fix: JS patch stores filter body in window._rxpFilterBody; getConversations when page > 1 redirects to POST /conversations/filter preserving the active filter.

Other patches (bugs 20-25)

  • Bug 20-22: query_operator regression, right-click context menu fix
  • Bug 23: assignee_type filter missing from Conversations::FilterService
  • Bug 24: LID stored as source_id after EvoGo JID swap collision
  • Bug 25: PipelineItem#days_in_current_stage N+1 with preloaded associations

Test plan

  • Deploy rxp_patches.rb to CRM container and restart Sidekiq
  • Confirm startup log: [RXP_PATCH] Bug 26 v2 -- EvolutionHandlers#raw_message_id keyId>messageId fix
  • Send a message via a WABA/Cloud API inbox and verify status progresses sent → delivered
  • Apply frontend JS patch and confirm active filter persists when scrolling to page 2+

🤖 Generated with Claude Code

Summary by Sourcery

Introduce a runtime patch bundle for evo-ai-crm-community rc5 that hot-fixes multiple backend and frontend issues around WhatsApp/Evolution integration, automations, pipelines, bots, and UI behavior without modifying upstream source.

Bug Fixes:

  • Ensure various controllers and models in Evo CRM behave correctly at runtime, including contact-company linking, pipeline item updates, OAuth applications listing, companies autocomplete, label CRUD, permission filtering, and conversations filtering by assignee type.
  • Correct WhatsApp Evolution/EvoGo handling for message IDs, JID/LID resolution, status updates, send.message events, media downloads, and template sync/creation so that messages, media, and templates are reliably processed and stored.
  • Prevent Aurora Copilot bots from sending unintended public replies, enforce inactivity-only triggering when configured, and auto-adjust conversation status based on Aurora’s private note category.
  • Resolve N+1 and performance issues in pipelines and pipeline items, including optimized eager loading, in-memory stage movement lookups, and label serialization without per-tag DB queries.
  • Mask sensitive WhatsApp and contact-related fields from Rails logs to avoid leaking personal data in Sidekiq and controller logging.
  • Fix EvolutionGo source_id and contact identifier persistence to avoid storing LIDs where JIDs/phone numbers are expected, restoring correct channel display and outgoing echo matching.
  • Preserve active conversation filters when paginating in the frontend so infinite scroll does not drop applied filters.
  • Address UI issues including a smart right-click context menu workaround and a WebSocket reconnection watchdog to keep the app responsive after long tab inactivity.

Enhancements:

  • Add a centralized runtime patches loader and supporting assets directory to encapsulate and document all hotfixes applied to evo-ai-crm-community rc5.

…crm-community rc5

Adds scripts/evocrm-patches/ with runtime patches for known issues in
evo-ai-crm-community:1.0.0-rc5, applied via rxp_patches.rb loaded through
Rails.application.config.to_prepare.

Bug 26 (critical): Aurora MESSAGES_UPDATE status never progressed past sent
  Root cause: Whatsapp::EvolutionHandlers::Helpers#raw_message_id preferred
  :messageId (Evolution API v2 internal Prisma ID) over :keyId (wamid =
  source_id in CRM). For Cloud API (WABA) inboxes, :messageId never matches
  any CRM message -- find_message_by_source_id returns nil and the status
  update is silently discarded.
  Fix: invert priority to :keyId || :messageId || dig(:key, :id)

Bug 27 (frontend): Active filter lost when paginating conversations
  Root cause: loadMoreConversations calls GET /conversations?page=N without
  active filters even when initial load used POST /conversations/filter.
  Fix: JS patch stores filter body in window._rxpFilterBody; getConversations
  when page>1 redirects to POST /conversations/filter preserving filters.

Also includes patches for bugs 20-25 (ContactCompany validator, pipeline items
N+1, LID/JID source_id collision, assignee_type filter, query_operator fix,
right-click context menu, days_in_current_stage sort).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a runtime monkey‑patch framework for Evo CRM (Rails + frontend) and implements fixes for bugs 1–27, with focus on Evolution/EvoGo WhatsApp integration, Aurora bot behavior, pipeline/conversation performance, and frontend filtering/pagination/right‑click behavior for evo-ai-crm-community rc5.

Sequence diagram for Evolution MESSAGES_UPDATE handling with raw_message_id keyId priority (bug 26)

sequenceDiagram
  participant EvolutionAPI as EvolutionAPI_v2
  participant IncomingService as IncomingMessageEvolutionService
  participant Helpers as Whatsapp_EvolutionHandlers_Helpers
  participant Message as MessageModel

  EvolutionAPI->>IncomingService: perform (messages.update payload)
  IncomingService->>IncomingService: process_messages_update
  IncomingService->>Helpers: raw_message_id
  Helpers-->>IncomingService: keyId || messageId || key.id
  IncomingService->>Message: find_message_by_source_id(raw_message_id)
  Message-->>IncomingService: existing_message
  IncomingService->>Message: update(status: delivered)
  Message-->>IncomingService: status_updated
  IncomingService-->>EvolutionAPI: ack
Loading

Sequence diagram for filtered conversations pagination preserving filters (bug 27)

sequenceDiagram
  actor User
  participant Browser as Browser_JS
  participant API as Api_V1_ConversationsController

  User->>Browser: apply filter (page 1)
  Browser->>Browser: filterConversations
  Browser->>Browser: window._rxpFilterBody = filter_body
  Browser->>API: POST /conversations/filter page=1 body=_rxpFilterBody
  API-->>Browser: filtered conversations page 1

  User->>Browser: scroll (loadMoreConversations page>1)
  Browser->>Browser: getConversations(page>1)
  Browser->>API: POST /conversations/filter page=N body=_rxpFilterBody
  API-->>Browser: filtered conversations page N

  User->>Browser: new search (page=1)
  Browser->>Browser: getConversations(page=1)
  Browser->>Browser: window._rxpFilterBody = null
  Browser->>API: GET /conversations page=1
  API-->>Browser: unfiltered conversations page 1
Loading

File-Level Changes

Change Details Files
Introduce rxp_patches.rb runtime patch loader to apply multiple Rails monkey‑patches at boot.
  • Wrap all patches in Rails.application.config.to_prepare for reload-safety
  • Conditionally patch only when target constants are defined to avoid load errors
  • Log each installed patch with an [RXP_PATCH] marker for observability
scripts/evocrm-patches/rxp_patches.rb
Fix Evolution WhatsApp helpers and handlers around LID, JID, media, and event routing (bugs 11, 16, 16b, 18, 19, 24, 26).
  • Add LID resolution via remoteJidAlt or fetchProfile, mutating @raw_message to ensure downstream jid_type/phone_number_from_jid see real JID
  • Add media download fallbacks for Evolution and EvoGo via chat/getBase64FromMediaMessage when webhook payload lacks usable media URLs
  • Route Evolution 'send.message' events to process_messages_upsert to correctly handle outgoing messages on Cloud API instances
  • Integrate Evolution template sync/create with API endpoints template.find/template.create, syncing statuses into CRM
  • Change raw_message_id to prioritize keyId over messageId for messages.update so status updates match CRM source_id
  • Adjust EvoGo MessagesUpsert to avoid storing LID as source_id/identifier, falling back to phone-derived values
scripts/evocrm-patches/rxp_patches.rb
Add Aurora bot behavior controls and auto-status transitions (bugs 13–15, 18).
  • Gate AgentBots::MessageCreator#create_bot_reply on bot_config['private_only'] to drop public replies for private-only bots
  • Gate BotRuntime::DelegationService#delegate on bot_config['inactivity_only'] to skip immediate dispatch and rely on inactivity jobs
  • Add Message after_create_commit hook to parse Aurora categoria prefix and transition conversation status based on a mapping
  • Ensure Aurora replies are persisted by handling Evolution send.message events as upserts
scripts/evocrm-patches/rxp_patches.rb
Improve LGPD/privacy and logging around WhatsApp payloads (bug 10).
  • Extend Rails filter_parameters with WhatsApp payload identifiers, media keys, and contact fields to mask them in logs
  • Log installation of the expanded filters for auditability
scripts/evocrm-patches/rxp_patches.rb
Fix conversations filtering, permissions, and companies list behavior (bugs 17, 20–23, 27).
  • Change AutomationRules::ConditionsFilterService#build_query_string to treat query_operator as leading, prepending it to the fragment
  • Guard Conversations::PermissionFilterService#perform against nil user, returning unfiltered conversations for service-token calls
  • Implement assignee_type handling in Conversations::FilterService#build_condition_query for me/assigned/unassigned values
  • Rewrite ContactsController#companies_list to return all named companies ordered alphabetically
  • Add frontend JS patch to persist filter body across pagination by storing it in window._rxpFilterBody and using POST /conversations/filter for page>1
scripts/evocrm-patches/rxp_patches.rb
scripts/evocrm-patches/index.html
Fix pipeline controller behavior and performance, including N+1 queries and params handling (bugs 2, 4, 5, 25).
  • Add before_action :set_pipeline_item to PipelineItemsController and permit pipeline_stage_id plus notes merged into custom_fields
  • Optimize PipelinesController index/show/fetch_pipeline with eager-loading for stages, items, and associated conversations/contacts
  • Ensure PipelineStage defines a stage_type enum when missing
  • Override PipelineItemsController#index to eager-load stage_movements, contacts (direct and via conversation), and labels, storing labels_by_title thread-local
  • Patch PipelineItem#days_in_current_stage to use in-memory sorting when stage_movements are preloaded
  • Patch ContactSerializer.serialize to attach labels using a precomputed labels_by_title map instead of per-tag queries
scripts/evocrm-patches/rxp_patches.rb
Repair ContactCompany linking, ContactCompaniesController error handling, Agents controller EvoAiCoreService usage, OAuth apps index, and label endpoints (bugs 1–3, 9, 12, 22).
  • Add no-op must_belong_to_same_account private method to ContactCompany when missing to satisfy validator
  • Fix ContactCompaniesController#create/destroy to call error_response with positional args instead of kwargs and return success payloads
  • Update AgentsController CRUD actions to call EvoAiCoreService without passing current_user as the first argument
  • Wrap Oauth::ApplicationsController#index response in {success,data,meta.pagination} structure expected by frontend
  • Make LabelConcern#index/create render JSON payloads instead of relying on missing views (avoiding 204 responses)
scripts/evocrm-patches/rxp_patches.rb
Add runtime JS patches for frontend right-click behavior and WebSocket resilience (and host bundle) via patched index.html.
  • Create a custom index.html that loads the upstream JS/CSS bundle and injects a right-click contextmenu fix that suppresses the first pointerup after opening the menu
  • Add a WebSocket watchdog that reloads the page when the tab returns from being hidden for >5 minutes to recover from stale WS connections
  • Ensure favicon and root div are preserved so the SPA behaves as expected
scripts/evocrm-patches/index.html

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • rxp_patches.rb has grown into a very large, multi-purpose monkey-patch file; consider splitting it into smaller, domain-focused modules (e.g., WhatsApp/Evolution, Aurora bot, pipelines, frontend shims) and requiring them from a lightweight entrypoint to make future maintenance and rollback safer.
  • Several runtime patches use class_eval/module_eval with direct method redefinitions (e.g., in Whatsapp::EvolutionHandlers::Helpers, ContactsController, PipelinesController); where possible, prefer prepend/Module wrappers or smaller, more targeted overrides so upstream method signature or behavior changes are less likely to be silently overridden in unexpected ways.
  • The inline JavaScript injected in index.html (right-click fix and WebSocket watchdog) hardcodes behaviors like the 5-minute WS stale threshold; consider moving this logic into a dedicated asset file and making key constants configurable so it’s easier to adjust or disable in different environments.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- rxp_patches.rb has grown into a very large, multi-purpose monkey-patch file; consider splitting it into smaller, domain-focused modules (e.g., WhatsApp/Evolution, Aurora bot, pipelines, frontend shims) and requiring them from a lightweight entrypoint to make future maintenance and rollback safer.
- Several runtime patches use class_eval/module_eval with direct method redefinitions (e.g., in Whatsapp::EvolutionHandlers::Helpers, ContactsController, PipelinesController); where possible, prefer prepend/Module wrappers or smaller, more targeted overrides so upstream method signature or behavior changes are less likely to be silently overridden in unexpected ways.
- The inline JavaScript injected in index.html (right-click fix and WebSocket watchdog) hardcodes behaviors like the 5-minute WS stale threshold; consider moving this logic into a dedicated asset file and making key constants configurable so it’s easier to adjust or disable in different environments.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant