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.