Developing Enterprise Edition Features
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