Deprecated: Creation of dynamic property wpdb::$categories is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$post2cat is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$link2cat is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/wp-db.php on line 668

Deprecated: Return type of WP_Theme::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-theme.php on line 554

Deprecated: Return type of WP_Theme::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-theme.php on line 595

Deprecated: Return type of WP_Theme::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-theme.php on line 535

Deprecated: Return type of WP_Theme::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-theme.php on line 544

Deprecated: Return type of WP_REST_Request::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/rest-api/class-wp-rest-request.php on line 960

Deprecated: Return type of WP_REST_Request::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/rest-api/class-wp-rest-request.php on line 980

Deprecated: Return type of WP_REST_Request::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/rest-api/class-wp-rest-request.php on line 992

Deprecated: Return type of WP_REST_Request::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/rest-api/class-wp-rest-request.php on line 1003

Deprecated: Return type of WP_Block_List::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 151

Deprecated: Return type of WP_Block_List::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 175

Deprecated: Return type of WP_Block_List::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 164

Deprecated: Return type of WP_Block_List::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 186

Deprecated: Return type of WP_Block_List::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 138

Deprecated: Return type of WP_Block_List::offsetExists($index) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 75

Deprecated: Return type of WP_Block_List::offsetGet($index) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 89

Deprecated: Return type of WP_Block_List::offsetSet($index, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 110

Deprecated: Return type of WP_Block_List::offsetUnset($index) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 127

Deprecated: Return type of WP_Block_List::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-list.php on line 199

Deprecated: Optional parameter $category declared before required parameter $page_number is implicitly treated as a required parameter in /var/www/html/uat.coloredcow.com/public/wp-content/mu-plugins/cc-employee-portal/class-ccemployee.php on line 114

Deprecated: Creation of dynamic property ACF::$fields is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/fields.php on line 136

Deprecated: Creation of dynamic property ACF::$locations is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/locations.php on line 130

Deprecated: Creation of dynamic property ACF::$json is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/json.php on line 184

Deprecated: Creation of dynamic property acf_loop::$loops is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/loop.php on line 26

Deprecated: Creation of dynamic property ACF::$loop is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/loop.php on line 270

Deprecated: Creation of dynamic property ACF::$revisions is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/revisions.php on line 413

Deprecated: Creation of dynamic property acf_validation::$errors is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/validation.php on line 26

Deprecated: Creation of dynamic property ACF::$validation is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/validation.php on line 212

Deprecated: Creation of dynamic property acf_form_customizer::$preview_values is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/forms/form-customizer.php on line 26

Deprecated: Creation of dynamic property acf_form_customizer::$preview_fields is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/forms/form-customizer.php on line 27

Deprecated: Creation of dynamic property acf_form_customizer::$preview_errors is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/forms/form-customizer.php on line 28

Deprecated: Creation of dynamic property ACF::$form_front is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/forms/form-front.php on line 603

Deprecated: Creation of dynamic property acf_form_widget::$preview_values is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/forms/form-widget.php on line 34

Deprecated: Creation of dynamic property acf_form_widget::$preview_reference is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/forms/form-widget.php on line 35

Deprecated: Creation of dynamic property acf_form_widget::$preview_errors is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/forms/form-widget.php on line 36

Deprecated: Creation of dynamic property InsertHeadersAndFooters::$plugin is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/insert-headers-and-footers/ihaf.php on line 41

Deprecated: Creation of dynamic property InsertHeadersAndFooters::$body_open_supported is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/insert-headers-and-footers/ihaf.php on line 48

Deprecated: Constant FILTER_SANITIZE_STRING is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/wp-smushit/core/modules/helpers/class-parser.php on line 229

Deprecated: Constant FILTER_SANITIZE_STRING is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/wp-smushit/core/modules/helpers/class-parser.php on line 234

Deprecated: Creation of dynamic property Smush\Core\Modules::$webp is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/wp-smushit/core/class-modules.php on line 95

Deprecated: Creation of dynamic property acf_field_oembed::$width is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/fields/class-acf-field-oembed.php on line 31

Deprecated: Creation of dynamic property acf_field_oembed::$height is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/fields/class-acf-field-oembed.php on line 32

Deprecated: Creation of dynamic property acf_field_google_map::$default_values is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/fields/class-acf-field-google-map.php on line 33

Deprecated: Creation of dynamic property acf_field__group::$have_rows is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/includes/fields/class-acf-field-group.php on line 31

Deprecated: Creation of dynamic property acf_field_clone::$cloning is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/pro/fields/class-acf-field-clone.php on line 34

Deprecated: Creation of dynamic property acf_field_clone::$have_rows is deprecated in /var/www/html/uat.coloredcow.com/public/wp-content/plugins/advanced-custom-fields-pro-5.8.7/pro/fields/class-acf-field-clone.php on line 35

Deprecated: Creation of dynamic property WP_Block_Type::$skip_inner_blocks is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-block-type.php on line 347

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: Creation of dynamic property WP_Post_Type::$singular_label is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-post-type.php on line 554

Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp.php on line 173

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/class-wp-term.php on line 198
ColoredCow




Multi-tenancy in Plio
Vaibhav Rathore
April 29, 2021

Planning the database schema for the new Plio infrastructure was easy. Or that’s what I thought initially.

The previous structure of Plio used to have various JSON files, each representing an entity on its own. For example, a typical user’s JSON file would look like this:

So, creating a database for users should be straightforward. Just convert all the JSON keys into columns. Well, not really.

Plio wasn’t just supposed to switch to a database. It needed a complete overhaul that includes a better structure and future readiness. Coming up with a solution that works for all scenarios and all organizations who choose to use Plio for their use cases.

So the structure we decided for supporting multiple organizations was fairly simple. A typical user can be a part of zero or more organizations and a super-admin will manage all the onboarded organizations. Similar to Notion, or Slack, or GitHub. This is where we brought in multi-tenancy.

There are three ways to implement any multi-tenancy system:

  1. Isolated Approach: Separate Databases. Each tenant (organization in our case) has its own database.
  2. Semi Isolated Approach: Shared Database, Separate Schemas. One database for all tenants, but one schema per tenant.
  3. Shared Approach: Shared Database, Shared Schema. All tenants share the same database and schema. There is a main tenant-table, where all other tables have a foreign key pointing to. Generally having a tenant_id column.

We decided to go with the second approach, as in our opinion, it was a good compromise for simplicity & performance and we get better things from both isolated and shared approaches.

There will be two kinds of schema in our database:

  1. Public schema
    This is a single schema containing information that doesn’t belong to a specific organization. Like users and organization data itself.
  2. Organization schema
    These are multiple schemas based on the number of organizations. Every organization schema will have the same set of tables. The benefit of having a semi-isolated approach was that we can have foreign keys referring to tables to public schemas which could’ve been a lot difficult in the isolated approach. Like user_id in a specific organization schema table.

We went with Django Tenant Schemas package to implement multi-tenancy in Plio. It’s built on the same principle of semi-isolated approach and was perfect for our use case.

Once the database was set up, we started experimenting with the REST API that we had set up with Django Rest Framework. The final challenge in our roadblock was to query the correct schema based on API requests. There were two things here:

  1. At the frontend app, detect the active workspace of the logged-in user. It can be a personal workspace or an organizational workspace. Based on this, we tell the backend about the active workspace through an HTTP header in the API request.
  2. At the backend, detect the HTTP request header and use it to query into the correct schema.

Here’s how we did it at both the ends.

Axios interceptor to add active workspace organization header before every API request was made.

Django middleware to set the schema connection based on organization header in the API request.

Now with everything in place, things seem like magic! Whenever a new organization is set up, the Django Tenant Schemas package automatically creates a new DB schema and maps it to the new organization. The logic above does the rest of the magic.


Deprecated: Creation of dynamic property WP_Query::$comments_by_type is deprecated in /var/www/html/uat.coloredcow.com/public/wp/wp-includes/comment-template.php on line 1528