Home Engineering Backend Guidelines

Backend Guidelines

Last updated on Apr 04, 2025

This document outlines the backend development guidelines specific to Chatwoot. All contributors are expected to follow these guidelines to ensure consistency, readability, and maintainability of the codebase.

Note: We follow the general Ruby on Rails development guidelines as mentioned in the official guide: Ruby on Rails Contributing Guide.

Project Structure

  • Follow Rails' default conventions and directory structure.

  • Organize code using service objects, concerns, and modules to keep controllers and models lean.

Design Principles

1. Single Responsibility Principle (SRP)

Each class or module should focus on a single responsibility.

✅ Good:

class AccountBuilder
  def initialize(user); @user = user; end

  def perform
    create_account
    setup_inbox
  end

  private

  def create_account
    # account creation logic
  end

  def setup_inbox
    # inbox setup logic
  end
end

❌ Bad:

class SetupEverything
  def execute
    create_account
    setup_inbox
    create_contact
    seed_conversations
  end
end

2. Minimal Namespace Pollution

Group helper classes and utilities under a shared namespace to avoid cluttering top-level modules.

✅ Good:

module TestData
  class AccountCreator
    def self.create; end
  end
end

❌ Bad:

class AccountCreator
  def self.create; end
end

3. Extract Long Methods

Split large methods into smaller private methods to improve readability and testability.

✅ Good:

def process_account_data
  validate_data
  transform_data
  persist_data
end

❌ Bad:

def process_account_data
  # 100+ lines of logic in one place
end

4. Avoid Side Effects in lib/tasks

Rake tasks should only serve as an orchestrator. Move core logic to services or jobs.

✅ Good:

# lib/tasks/seed.rake
namespace :db do
  task seed: :environment do
    Seed::AccountSeeder.new.run
  end
end

❌ Bad:

# lib/tasks/seed.rake
namespace :db do
  task seed: :environment do
    Account.create!(...) # all logic directly in rake task
  end
end

5. Clear Naming

Name variables and methods in a way that clearly communicates their purpose.

✅ Good:

def generate_contact_for_account(account_id); end

❌ Bad:

def gen_contact(id); end

Code Style

  • Use 2 spaces for indentation.

  • Use snake_case for methods and variables.

  • Use CamelCase for class and module names.

  • Avoid trailing whitespace.

  • Run rubocop before committing changes.

Pull Request Guidelines

Refer to our Pull Request Guidelines for best practices on how to structure, describe, and submit your changes.

API Design

  • Follow RESTful conventions.

  • Use JSON:API specification for consistency.

  • Version APIs (e.g., /api/v1/...).

  • Use proper status codes and include error messages in a standard format.

  • Document all new endpoints by following the Swagger Documentation Guide.

Background Jobs

  • Use Sidekiq for background processing.

  • Name jobs with the Job suffix (e.g., ContactMergeJob).

  • Keep jobs idempotent and retry-safe.

Database

  • Use migrations for schema changes.

  • Avoid writing raw SQL unless necessary.

  • Use PostgreSQL features (e.g., JSONB, GIN indexes) when beneficial.

  • Index foreign keys and columns used in queries.

Testing

  • Use RSpec for all tests.

  • Write unit, request, and system tests.

  • Aim for high test coverage, especially on critical paths.

  • Use FactoryBot for setting up test data.

Security

  • Never trust user input; sanitize and validate.

  • Use strong_parameters in controllers.

  • Avoid dynamic eval, send, or string interpolation in SQL.

Performance

  • Profile slow endpoints using tools like rack-mini-profiler or Skylight.

  • Use N+1 detection tools (e.g., Bullet) during development.

  • Cache where appropriate, but invalidate caches correctly.

Documentation

  • Document all new endpoints in the API reference.

  • Add inline comments for complex logic.

  • Update the handbook or README if behavior changes.


By adhering to these practices, we ensure that Chatwoot remains a scalable, maintainable, and developer-friendly codebase.