Home Engineering


Articles on engineering practices at Chatwoot.
Pranav Raj Vishnu Sojan
By Pranav Raj and 3 others
12 articles

Frontend Guidelines

This guide explains the best practices, patterns used in frontend development. Events vs. props for methods in Vue Components Prefer events instead of passing a function down to the component. This helps you to write @methods on the component. Read the official doc on listening to child components here. // Bad <template> <child-component :on-close="handleClose" /> </template> // Good <template> <child-component @close="handleClose" /> </template> Usage of computed properties While having logic or conditions inside the Vue template, prefer writing a computed property than a complex logic. // Bad <template> <child-component :is-available="a > b && c - d === 2" /> </template> // Good <template> <child-component @close="handleClose" /> </template> <script> export default { computed() { isAvailable() { return this.a > this.b && (this.c - this.d) === 2 } } } </script> Use CSS Variables instead of SCSS variables We have CSS variables defined for spacing, font size, colors, etc., instead of importing SCSS variables in the dashboard. We are promoting the Usage of CSS variables as it helps us to customize the dashboard during runtime. Follow semantics while writing HTML Avoid using block dom nodes like div, section, etc to wrap text inside HTML. Read more about HTML semantics here Note on accessibility - Use alt tags for all images you have added to the code. - Use an anchor tag to place links to other pages, do not use it to create a link button. Read about accessibility here CSS naming convention. Follow BEM guidelines for CSS naming. While planning DOM structuring to adapt the style needed for CSS, keep it simple and readable. If possible, use pseudo selectors as an alternative to dummy dom nodes just for use in CSS styling. More on this here Note: We have used OOCSS at places that need to be rewritten. The naming convention for vuex actions All the CRUD API actions should follow the same name as Rails APIs. See the following example. fetchAllHelpCenters => index fetchOneHelpCenter => show createHelpCenter => create updateHelpCenter => update deleteHelpCenter => delete This makes it easier to read and understand the methods. For e.g.: Instead of portals/fetchAllHelpCenters, this becomes portals/index. Avoid manipulating DOM directly In most cases, there is no need to manipulate the DOM directly. Use Vue methods and state to change the DOM elements. Vue is data-driven, and thus, its features are built around this concept and do not encourage manipulating the DOM “the jQuery way.” If you want to access DOM directly, use this.$refs.

Last updated on Apr 17, 2023

Swagger Documentation

Chatwoot maintains its API documentation using swagger. Therefore, whenever you commit an API change to Chatwoot, The associated swagger Documentation needs to be updated. This guide will walk you through adding documentation for a new endpoint in Chatwoot's swagger.json. The guide uses Canned Responses as the example object for documentation. Prerequisities You can access swagger documentation for the Chatwoot app in your local installation over: http://localhost:3000/swagger The commands to update your swagger.json is as follows. rake swagger:build If you are familiar with the process, need a sample reference, head over to the example Pull Request Steps to add a new endpoint 1. Define Tag in swagger index Define the Tag for the object to be added in swagger/index.yml. Since we want this endpoint under Application APIs, it is added under the name Application. see the changes in reference commit 2. Add the resource definition Add the resource definition and its attributes to a definition file. You should place the resource definition file in the root or a sub folder of swagger/definitions/resource. Don't forget to add the resource definition path to index in swagger/definitions/index.yml In our case for the Canned Response, we are placing it in swagger/definitions/resource/canned_response.yml see the changes in reference commit 3. Define request payloads The next step is to define the request payloads. You can split methods like create, update etc. into single or multiple files based on your requirement. Also, make sure to add the paths to the index. Ensure to add the response payload definition path to index in swagger/definitions/index.yml In our case of Canned Response, since the payload is the same for both create and update, we are adding it in swagger/definitions/request/canned_response/create_update_payload.yml see the changes in reference commit 4. Define request paths Define the required paths for the endpoint to swagger/paths/index.yml. Create appropriate files for each route. In the path definitions, you can reference the request objects defined in step 2 and params from step 3. For Canned Response, we are defining the following path files. swagger/paths/application/canned_responses/create.yml swagger/paths/application/canned_responses/delete.yml swagger/paths/application/canned_responses/index.yml swagger/paths/application/canned_responses/update.yml see the changes in reference commit 5. Build and verify Run rake swagger:build and verify the updated documentation at http://localhost:3000/swagger. If there are build errors, you will see them while loading the documentation in the browser. Fix the issues and re-run build until the documentation is ready. Then, raise a PR with the changes. Ensure to commit the newly generated /swagger/swagger.json. see the changes in reference commit Updating Chatwoot API docs page If you are a community contributor, The PR reviewer will take care of this step. Updating the swagger documentation on https://www.chatwoot.com/developers/api/ requires a commit on the chatwoot-website repo. You should copy the contents of newly generated swagger.json and update the following files in the chatwoot-website repo src/data/swagger/swagger-develop.json src/data/swagger/swagger.json see the changes in reference pull request

Last updated on Apr 17, 2023

Pull Request Guidelines

Avoid Cosmetic Changes Chatwoot generally doesn't accept cosmetic changes and does not add anything substantial to the stability, performance, functionality, or testability. Examples: - Cosmetic copy changes or trivial mistakes - Trivial code changes like variable renaming or cosmetic fixes - Copy/Help text changes - Changes suggested by code linters or automated tools The reasoning behind this decision is due to hidden costs like the following. - Copy/Help text changes cause significant effort for the community translators as they will have to retranslate the string across all the languages. Learn more about the translation process here - It takes away time and energy the team could spend on critical features and bug fixes. - It pollutes the git history as git blame hits the refactor commits and makes it harder to understand the original decision-making. To Avoid confusion, please discuss the changes over a GitHub issue before starting the work. The thought process here is inspired by Ruby on Rails Contribution guide. Raising a pull request Points to note when you are raising a PR. - Try to make the review cycle short. - Make sure code follows the style guidelines of this project - Perform a self-review of your code. - Commented on the code, particularly in hard-to-understand areas. - Make necessary changes in the documentation. - Verify that the PR does not generate new warnings. Check rails console as well as browser console. - Add tests to prove that the fix is effective or that the feature works. - New and existing unit tests pass with the changes. - Any dependent changes have been merged and published in downstream modules. Ownership For all external and internal contributions to Chatwoot repositories, the team will triage the pull request and assign a PR owner. At any point in time, the assignee field in Github shows the PR owner responsible for taking some action. The PR owner will work with the PR author to provide review comments, assist in testing or re-assigning the pull request to another owner when required. PR raised by a team member The ownership of the PR is on the person who creates the PR. The PT author's responsibility is to get it reviewed, QA'ed, and merge it to production. When a PR is ready for review, the PR author can assign the PR to people from whom they would like to get a review. Once the review is done, the reviewer can un-assign themselves from the ticket. The last reviewer would un-assign themselves and assign it back to the author. PR raised by a community member The on-call person would triage the PR and add an assignee to the PR. Ownership is on reviewers to get it merged. Commit message Please ensure that the commit message is a proper sentence before merging a pull request and has full context about the PR in the description. Here is a guide on writing good commit messages. (https://chris.beams.io/posts/git-commit/) - A properly formed git commit subject line should always be able to complete the following sentence If applied, this commit will your subject line here - Capitalize the subject line Commit Message Structure A commit message should be structured as follows. <type>[optional scope]: <description> [optional body] [optional footer(s)] Type should follow Conventional Commit Specification. You can read more about the type and conventional commit specification here. https://www.conventionalcommits.org/en/v1.0.0-beta.2/#summary Update product documentation Please make sure that product docs are updated before merging the PR. In addition, the PR owner should check the requirement of any documentation changes related to the raised PR. - Add the docs-needed label to the PR. - Add the content to the docs, - Add docs-done label to the PR after completing the documentation. Add co-authors if applicable It is essential to add attribution to people who have contributed to the pull request. Please use Co-authored-by: at the end of the description. Commits in branches We use commit squashing to merge a PR to develop or release branches. Avoid force-push to remote branches / Pull Requests Avoid force-pushing your changes when working on a public branch and you face a merge conflict. Rewriting history through force-push can have the following side effects. - Changes made by others could be lost - It could mess up previous review comments on Github - Other contributors of the branch will have to delete and re-fetch the branch Hence one should pull the upstream changes, resolve the merge conflict via a merge commit and then push the changes. Use rebase to avoid merge commits in local note: The golden rule of git rebase is to never use it on public branches. ref A merge commit is created if the local and remote branches have different commits when you pull without the --rebase flag. Therefore, it is good to rebase your local commits. To avoid typing --rebase every time you can configure git to use it as default: git config --global pull.rebase true

Last updated on Apr 17, 2023

Release Process

At Chatwoot, we follow a monthly release schedule. On the 15th of every month, we will release a new software version. To release the version of the software, use the following guide. Github release process We use git-flow as our branching strategy. 1. Pull the latest changes Pull latest develop branch and master branch in your local machine. git checkout master git pull git checkout develop git pull git fetch --tags 2. Prepare release # find the appropriate version by looking into `config/app.yml` git flow release start '1.12.0' # replace your version number 3. Bump the version number now - Bump up the version numbers in the following files. - config/app.yml - package.json - Commit the changes to develop branch with a title Bump version to #{version_number} See this commit for example: Bump version to 1.11.1 · chatwoot/chatwoot@a214372 4. Start committing last-minute fixes in preparing your release 5. Finish release git flow release finish '1.12.0' # replace your version number # Leave default merge messages as it is # prepare the tag message as 'v1.12.0' # replace your version number 6. Push changes to remote Branch protection might be enabled for the master branch. In that case head over to github settings and have it disabled for admins before pushing the changes. You should renable it after finishing the process Push master branch, develop branch and the tags. # Push develop git checkout develop git push --no-verify # Push master git checkout master git push --no-verify # Push tags git checkout develop git push --tags --no-verify 8. Prepare release notes - Compare the current version to the previous version using the tag compare feature in Github. https://github.com/chatwoot/chatwoot/compare/v1.11.1...v1.12.0 - Create a new release on Github from existing tags and update release notes. - Ensure that the milestones exist for the subsequent 2 versions. - Close the current milestone and move issues to the next milestone. Release note format: - Describe the changes in the current release - List the new languages that are added in the new release - Gratitudes towards who have contributed to the project. Release note example: ## Changelog - Ability to detect contact location - Ability to download Agent reports - Search contacts using the phone number - Set up dev environments with GitHub codespaces - Ability to set Installation wide default language - Improved alerts on agent/user typing - Limit file types that can be attached - Ability for external systems to authenticate users into Chatwoot using tokens - Numerous bug fixes and enhancements - New Languages - Danish - Korean - Czech - Turkish - Finnish - Indonesian ### Thanks to @azyzio, @hiaselhans, @vishal-pandey, @troscoe, @timcowlishaw, @mike9011 for the contributions Todos after Github release - Create release notes in Changelog (https://chatwoot.com/changelog). If you don't have access to the blog, please contact Pranav / Sojan. - Update the latest version in Chatwoot Hub. This is used to show a notification to users using self-hosted installation. - Create tasks in Product board to deploy the changes to our paid clients. Hotfix Releases Follow the same release process except for the git flow release commands. Replace the commands with git flow hotfix instead. # example git flow hotfix start '2.8.1' git flow hotfix finish '2.8.1' Note: Make sure that the hotfix release branches are branched off from master instead of develop.

Last updated on Apr 17, 2023

Speed up your local development workflow with Make

Speed up your local development workflow with make commands. Clone the repo and cd to the Chatwoot directory Clone the repository and navigate to the Chatwoot directory: git clone https://github.com/chatwoot/chatwoot.git cd chatwoot Install Ruby & JavaScript dependencies Install Ruby and JavaScript dependencies using the following command. This command runs Bundler and Yarn: make burn Run database migrations Apply necessary database schema changes to your development environment by running the following command: make db Run dev server using Overmind Start the development server using Overmind, a process manager that can run multiple processes concurrently: make run Force run if ./.overmind.sock file exists If the make run command fails due to the existence of a ./.overmind.sock file, you can try using the following command: make force_run Debug - Attach to backend via Overmind tmux session For debugging purposes, you can attach to the backend via the Overmind tmux session using the following command: make debug Debug worker To debug the worker, use the following command: make debug_worker Get Rails console Access the Rails console, which provides an interactive environment for interacting with the Chatwoot application: make console Build Docker image Build the Docker image for the Chatwoot project: make docker Workflow after pulling in the latest changes from develop To update your development environment after pulling the latest changes from the develop branch, follow these steps: make burn # Install dependencies make db # Run migrations make run # Start the server

Last updated on Nov 01, 2023

Translation Guidelines

Never split sentences and join them using string concat operation https://www.loom.com/share/79867e90be754f97a28f6c39aa5b4239 Translations usually aren't performed word-for-word due to varying language structures, idioms, and cultural nuances. A literal translation, which is a word-for-word rendition, often struggles to effectively communicate the original meaning and can lead to awkward or nonsensical text. We will illustrate this through an example. Consider the following sentences: 1. We will be back online in some time. 2. We will be back online at 9 AM. 3. We will be back online on Monday. 4. We will be back online in 10 minutes. To support internationalization (i18n), you could either draft it as four distinct sentences or a single primary sentence combined with different time phrases. The primary sentence would be We will back online, and the four different time phrases can be: - "in some time" - "at 9 AM" - "on Monday" - "in 10 minutes" By doing so, you can combine the primary sentence with any of the time phrases to create accurate translations. As a developer this might seem like a good idea, but it is not. Let's take the example of "We will be back in some time". We will be back translates to ഞങ്ങൾ തിരിച്ചു വരും in Malayalam and हम वापस आ जाएंगे in Hindi. In some time translates to കുറച്ച് സമയത്തിനുള്ളിൽ in Malayalam and कुछ समय में in Hindi. The combined sentences are as follows: In Malayalam: ഞങ്ങൾ തിരിച്ചു വരും കുറച്ച് സമയത്തിനുള്ളിൽ. In Hindi: हम वापस आ जाएंगे कुछ समय में. As you can observe, the natural flow of the sentence is broken. This leads to awkward sentences in complex cases as the translator doesn’t know the full context of the sentence.

Last updated on Apr 26, 2024