Home Enterprise Edition Developing Enterprise Edition Features

Developing Enterprise Edition Features

Last updated on Jul 05, 2023

Chatwoot ships two versions of its software, a Community Edition and an Enterprise Edition. This guide focuses on the engineering best practices while developing features for the Enterprise edition.

The guidelines followed in Chatwoot's Enterprise edition development are heavily inspired by the model adopted by Gitlab, and hence their guide is an excellent reference to learn more.

Testing Community Edition

Chatwoot team should be developing features over the Enterprise Edition in their local development environments by default. You can test how the community edition will behave by toggling the environment variable DISABLE_ENTERPRISE to true and restarting Chatwoot Server.

Organization of Code

The JavaScript part of Chatwoot code is completely MIT, while enterprise separation is applied over the ruby code concerning the backend Chatwoot APIs and Services. Always place Enterprise edition proprietary code under the top-level enterprise directory. In addition, the modules should follow the structure as close to their Community Edition counterparts (See the specifics in sub Sections).

The enterprise edition specs should reside in the spec/enterprise folder.

How to develop features

For Community Edition features, you can follow the general best practices for Ruby on Rails and Vue.js Development. But when you identify an exclusive feature or Enterprise edition extension, you must follow the appropriate guidelines mentioned below.

General Guidelines

JavaScript

The JavaScript part of Chatwoot code is available under MIT. But you might want to limit the visibility of specific components based on the edition of Chatwoot Version. In such cases, you can rely on the helper method isEnterprise() available in app/javascript/shared/mixins/configMixin.js. Then, include the mixin in your Component and implement a conditional check to render the sub-component appropriately.

Helpers in ruby Code

While working in the ruby code, ChatwootApp.enterprise? helper is available for you to determine whether the user is running the Enterprise Edition of the software.

Data Models & Data Migrations

Users could be migrating between versions. So we always have to ensure that all the migrations are run for both the edition. The database schema needs to remain the same for both editions. In the Case of DataMigrations, you can have blank implementations for these migrations by conditionally excluding Enterprise specific DataModels with ChatwootApp.enterprise?

Routes

If you want to limit the access of a specific route to Enterprise Edition alone, use the ChatwootApp.enterprise? helper.

  if ChatwootApp.enterprise?
    get '/enterprise', to: 'dashboard#enterprise'
  else

Developing features as an extension of Community Edition

When developing Enterprise features built over the Community Edition software, Implement a base functionality in Community edition code and extend it over in an Enterprise licensed module.

As shown in the example, we write a module in the Enterprise namespace and inject it into the community edition class.

# app/models/inbox.rb
class Inbox < ApplicationRecord
  # placeholder method which will be overriden in Enterprise edition
  def member_ids_with_assignment_capacity
    members.ids
  end
end

Inbox.prepend_mod_with('Inbox')
# enterprise/app/models/enterprise/inbox.rb
module Enterprise::Inbox
  def member_ids_with_assignment_capacity
    super - get_agent_ids_over_assignment_limit
  end

  private

  def get_agent_ids_over_assignment_limit
    # implement proprietry enterprise logic
  end
end

You can use the helper methods like prepend_mod_with, extend_mod_with, or include_mod_with, depending on how you want to include the enterprise method into the chain. Refer InjectEnterpriseEditionModule to learn more.

Ensure that the module written to extend the Community Logic is put under the Enterprise namespace.

# notice the extra namespacing with in models directory
# enterprise/app/models/enterprise/inbox.rb

# other examples
# enterprise/app/controllers/enterprise/paid_feature_controller.rb
# enterprise/app/builders/enterprise/paid_builder.rb

Developing features exclusive in the Enterprise Edition

If the feature is not present in Community Edition, we must directly put the code into the enterprise directory without the enterprise namespace. This works because we have the enterprise directory in autoload paths.

# no need for extra enterprise namespacing since we aren't prepending 
# enterprise/app/controllers/paid_feature_controller.rb
# enterprise/app/models/paid_feature.rb

CI Pipeline for Community Edition

We run a Community Edition pipeline over all the pull requests raised against Chatwoot to ensure that the updates don't break existing features in the CE edition. This pipeline ensures stability by stripping off the enterprise folder from the codebase and running the full suite of tests against Chatwoot.

Troubleshooting

My module does not prepend/initialize

This could be a problem with the directory; if you notice the directory structure, we have and enterprise folder inside models as well. If you're adding anything to models/enterprise or lib/enterprise. Suppose you're adding a new namespace called extras; ensure an enterprise folder is inside it.

Constants declared are not accessible when prepending

This happens because prepend does not allow accessing the values across ancestors, you can access those using self.class::CONSTANT_NAME