Skip to content

evolution-foundation/evo-ai-crm-community

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

488 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Evolution Foundation

Evo CRM Backend

Conversations, contacts, inboxes and messaging backend for the Evo CRM Community.

Latest version License: Apache 2.0 Documentation Community

Website · Documentation · Community · Support


About

Evo CRM Backend is the core API of the Evo CRM Community customer support platform. Built with Ruby on Rails 7.1 (API mode), it manages conversations, contacts, messages, inboxes, and integrations across multiple communication channels (WhatsApp, Email, Web Widget, and more).

It exposes a comprehensive RESTful API and supports real-time messaging via ActionCable WebSockets.

Part of the Evo CRM Community

Evo CRM Backend is part of the Evo CRM Community ecosystem maintained by Evolution Foundation. To use the full stack, clone the umbrella repository with submodules:

git clone --recurse-submodules git@github.com:evolution-foundation/evo-crm-community.git

The Community Edition is single-tenant by design — one account, no multi-tenancy overhead, no super-admin, no billing or plans. All limits are removed and features are unlocked by default.


Tech Stack

Component Technology
Backend Ruby on Rails 7.1 (API mode)
Ruby 3.4.4
Database PostgreSQL
Cache & Jobs Redis + Sidekiq
Real-time ActionCable (WebSocket)
Authentication Bearer token via evo-auth-service-community
File storage AWS S3, Google Cloud Storage, Azure Blob

Quick Start

Prerequisites

  • Ruby 3.4.4
  • PostgreSQL 12+
  • Redis 6+
  • pnpm (optional, for convenience scripts)

Installation

git clone git@github.com:evolution-foundation/evo-ai-crm-community.git
cd evo-ai-crm-community

# Install dependencies
bundle install
pnpm install  # Optional — for convenience scripts

# Setup database
bundle exec rails db:setup
bundle exec rails db:migrate

Running

# Using pnpm (recommended)
pnpm dev          # Rails + Sidekiq
pnpm start        # Rails only
pnpm sidekiq      # Sidekiq only

# Using Overmind / Foreman
overmind start -f Procfile.dev

# Manual
bundle exec rails server -p 3000
bundle exec sidekiq -C config/sidekiq.yml

The API will be available at http://localhost:3000.


Configuration

Copy .env.example to .env and configure:

# Database
DATABASE_URL=postgresql://localhost/evolution_crm_development

# Redis
REDIS_URL=redis://localhost:6379/0

# Optional: ScyllaDB for high-performance message storage
SCYLLA_ENABLED=true
SCYLLA_HOSTS=localhost
SCYLLA_PORT=9042
SCYLLA_KEYSPACE=evo_crm

# Frontend URL (CORS)
FRONTEND_URL=http://localhost:8080

# Storage (S3, GCS, Azure)
ACTIVE_STORAGE_SERVICE=local

See .env.example for the full list.


Available Scripts

Script Description
pnpm dev Start Rails + Sidekiq
pnpm start Start Rails server
pnpm test Run RSpec tests
pnpm lint Run RuboCop
pnpm lint:fix Run RuboCop with auto-fix
pnpm db:setup Setup database
pnpm db:migrate Run migrations
pnpm db:seed Seed database
pnpm console Rails console
pnpm sidekiq Start Sidekiq worker

Architecture

API-only mode

The application runs in Rails API mode — no frontend views. The frontend is developed separately (evo-ai-frontend-community).

Service objects

Business logic is organized in service objects:

app/services/
├── base/
│   └── send_on_channel_service.rb
├── whatsapp/
│   └── message_processor_service.rb
└── crm/
    └── contact_sync_service.rb

Event-driven (Wisper)

Domain events are published for cross-cutting concerns:

  • contact.created
  • conversation.resolved
  • message.sent

Background jobs (Sidekiq)

Heavy operations run asynchronously: external API calls, webhook processing, bulk operations.


API

Base URL

http://localhost:3000/api/v1

Authentication

Bearer tokens issued by evo-auth-service-community:

curl -H "Authorization: Bearer YOUR_TOKEN" \
     http://localhost:3000/api/v1/conversations

Documentation

Swagger UI available at http://localhost:3000/swagger.

For full API documentation, see docs.evolutionfoundation.com.br.


Features

  • Real-time messaging via ActionCable WebSockets
  • Multi-channel support (WhatsApp, Email, Web Widget, and more)
  • RESTful API with comprehensive Swagger documentation
  • High-performance messages with optional ScyllaDB (<1ms latency)
  • Background jobs with Sidekiq
  • Event-driven architecture for extensibility
  • File storage support for S3, GCS, Azure Blob
  • Rich message templates with drag-and-drop editor

Testing

# All tests
pnpm test
# or
bundle exec rspec

# Specific file
bundle exec rspec spec/models/contact_spec.rb

# Specific test
bundle exec rspec spec/models/contact_spec.rb:42

Linting

# Check
pnpm lint
# or
bundle exec rubocop

# Auto-fix
pnpm lint:fix
# or
bundle exec rubocop -a

Docker

docker-compose build
docker-compose up

# Specific services
docker-compose up backend worker

Maintenance tasks

Legacy template migration (EVO-1234)

Ports channel-coupled message templates (rows with channel_id NOT NULL) into the global/independent flow introduced by EVO-1231, creating a channel-less (channel_id IS NULL) counterpart for each. WhatsApp Cloud templates are intentionally not migrated — Meta requires an approved template tied to a WABA channel, so they stay channel-bound.

# 1. Preview — logs the counts that would migrate, writes nothing
DRY_RUN=true bundle exec rake templates:migrate_legacy

# 2. (Recommended) back up the table before applying in production
pg_dump -t message_templates "$DATABASE_URL" > message_templates_backup.sql

# 3. Apply — idempotent, safe to rerun (provenance tracked via external_legacy_id)
bundle exec rake templates:migrate_legacy

# Rollback — deletes ONLY migrated globals (external_legacy_id IS NOT NULL);
# channel-bound originals and admin-created globals are untouched.
bundle exec rake templates:rollback_legacy_migration

Notes:

  • Idempotent: rerunning never duplicates (each copy carries external_legacy_id = "message_template:<source_id>", backed by a partial unique index).
  • Rollback caveat: rollback also discards any admin edits made to migrated templates after the migration ran.
  • Best run after the template menu UI (EVO-1233) is available so an admin can visually validate the migrated globals.
  • The migration emits Prometheus counters (templates_migrated_total{source}, templates_migrated_skipped{reason}), but the authoritative result is the summary printed by the rake task and the structured log lines — the counters increment in the worker process and are not exposed to the web /metrics scrape.

Documentation

Resource Link
Website evolutionfoundation.com.br
Documentation docs.evolutionfoundation.com.br
Community evolutionfoundation.com.br/community
Swagger http://localhost:3000/swagger
Changelog CHANGELOG.md
Contributing CONTRIBUTING.md
Security SECURITY.md

EvoFlow integration

Canonical event names

The authoritative list is lib/events/evo_flow_event_names.rb (EvoFlow::EVENT_NAMES, 16 dot-notation strings, frozen). EvoFlow::PayloadBuilder.build_track and .build_identify raise EvoFlow::InvalidEventName if a caller passes a name outside the list. The same list is mirrored in evo-flow/src/modules/events/event-names.enum.ts, and a CI script (scripts/check-event-names-sync.sh at the monorepo root) blocks PRs that drift.

Growing the list: adding or removing an entry requires three coordinated edits in the same PR: lib/events/evo_flow_event_names.rb (this repo), src/modules/events/event-names.enum.ts (in evo-flow), and the EXPECTED_COUNT constant in scripts/check-event-names-sync.sh (in the evo-crm-community monorepo). Otherwise the sync job fails with DIVERGENT — lists match each other but count is N (expected M).

Backfill EvoFlow contact_events

EvoFlow::BackfillContactEventsWorker ports historical Message(message_type: :activity) and ReportingEvent rows to evo-flow's ClickHouse via the /events/batch endpoint so the contact-events timeline (consumed by EvoFlow::PublishEventWorker's downstream surface) is populated for contacts that existed before the live publisher shipped.

⚠️ Do NOT run with DRY_RUN=false in production until evo-flow's IdempotencyService is deployed. Without consumer-side dedup, reruns duplicate events in ClickHouse (contact_events is a plain MergeTree). The rake task hard-stops on Rails.env.production? && !DRY_RUN && CONFIRM != I_KNOW_WHAT_IM_DOING for this reason.

1. Dry-run (default — counts and logs a single sample payload, no POST):

bundle exec rake evo_flow:backfill                  # ALL records
bundle exec rake evo_flow:backfill DRY_RUN=true     # same, explicit

Watch the Sidekiq worker log for lines prefixed [EvoFlow][Backfill]:

  • would_backfill account=ALL type=message count=<n> (per source)
  • sample_payload=... (exactly one, payload of the first item)

2. Inspect counts in ClickHouse (after a real publish):

SELECT count() FROM contact_events WHERE message_id LIKE 'backfill|%';

The messageId is SHA256("backfill|<source>|<id>") and backfill| is the rollback selector.

3. Real publish (dev / staging):

DRY_RUN=false bundle exec rake evo_flow:backfill

4. Real publish (production — requires CONFIRM):

DRY_RUN=false CONFIRM=I_KNOW_WHAT_IM_DOING bundle exec rake evo_flow:backfill

5. Custom date window (default is 1.year.ago — matches the 365-day ClickHouse TTL on contact_events):

FROM_DATE=2026-04-01T00:00:00Z bundle exec rake evo_flow:backfill

Rollback (manual, on the evo-flow ClickHouse host):

ALTER TABLE contact_events DELETE
WHERE message_id LIKE 'backfill|%'
  AND occurred_at >= toDateTime('2026-05-01 00:00:00');

Known limitations:

  • Events older than 365 days are not iterated (matches ClickHouse TTL).
  • Notes are not portable (kept in the CRM panel — out of scope).
  • Without the evo-flow IdempotencyService, reruns duplicate events. The cursor survives crashes and is partitioned by the from_date window (backfill:cursor:<yyyy-mm-dd>:message / …:reporting_event in Redis::Alfred), so changing FROM_DATE does not silently skip records.

Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines on how to submit issues, propose features, and open pull requests.

Join our community to discuss ideas and collaborate.


Security

For security issues, do not open a public issue. Email suporte@evofoundation.com.br or use GitHub's private vulnerability reporting. See SECURITY.md for details.


License

Evo CRM Backend is licensed under the Apache License 2.0. See LICENSE for details.

Trademarks

"Evolution Foundation", "Evolution" and "Evo CRM Backend" are trademarks of Evolution Foundation. See TRADEMARKS.md for the brand assets policy.

Third-party attributions are documented in NOTICE.


Made by Evolution Foundation · © 2026

About

No description, website, or topics provided.

Resources

License

Contributing

Security policy

Stars

16 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors