Designing a content management system backend

Adwait Mathkari
4 min readOct 17, 2022

--

In this article, I will present a case study of the development of a ‘Content Management System’ backend which was developed for the website of a leading UK based journal.

An example journal website

The requirements of the system were as follows: The systems should provide capabilities to create content, manage content, deliver content to users, where content includes text, images, videos, links, text cards, tables, page formats etc.

Architecture Overview

A microservices based architecture was used and the CQRS design pattern was used since the volume of reads was much higher than the volume of updates to the database. Thus, services reading the database and ones updating, inserting into the database were kept segregated.

CQRS stands for Command and Query Responsibility Segregation, a pattern that separates read and update operations for a data store. Implementing CQRS in your application can maximize its performance, scalability, and security. The flexibility created by migrating to CQRS allows a system to better evolve over time Designing a content management system backend
In this article, I will present a case study of the development of a ‘Content Management System’ backend which was developed for the website of a leading UK based journal.and prevents update commands from causing merge conflicts at the domain level.

High level architecture diagram was as follows:

Simplified Architecture Diagram

The publishing service, the compose service were primarily for receiving content from the content publishing UI and for processing the data for storage in the database. The delivery service was used to deliver queried content.

Contentful was used as the frontend UI tool for creating the content. Contentful’s rich component list and overall features helped to create the expected user experience. The ‘content’ was then exported from contentful using their webhooks into the backend system.

Cloudflare was used as a caching layer, as a content delivery network at edge locations and as a security layer to prevent malicious attacks on the systems.

Database design, Data Structures, logic:

The Content was structured in a tree/graph like data structure. Any component for example a card, an image, a hyperlink, a paragraph, an article etc was a separate node. Each node was created separately in the contentful UI and then could be reusably attached to another component. For example, you can create a card component and attach it to an article component. The article could have a list of cards attached to it. Further, each card component will have an image component, a title component, a hyperlink component as children. Thus a full article would be a tree with article as a root and various children attached to it and further their children etc.

Content Data Structure

Each node was stored in DynamoDB as a row. Each component would have a unique key as entityId and any parent component would reference this entityId in its fields in order to reference a child. In the above example, the paragraphs, the cards and the downloadable components would be referenced with entityId in the article component. Further, image and text components would be referenced in a paragraph component and so on. Thus to get a full article, one would need to get the root article component and then query the children in the DB, and then further query the children’s children and form the complete data by stitching these together.

Initially, the approach was to generate a tree at runtime, since the maximum depth estimated was around 10 and using an breadth first traversal that would mean 10 queries one after the other to the database. Since all queries would be on the entityId and dynamoDB promising single digit millisecond querying, the time needed to make these queries would not be that much.

In further iterations, the final approach was taken to store the complete tree in a separate table and when returning an article, return that one already constructed object. Although, this would mean that whenever any single component was updated, you would need to traverse to all its parents and update the value of this component in their generated trees. Thus if an image component was updated, it would need to be updated in all the cards or paragraphs or articles where this component exists as a direct or indirect child. This was done by maintaining a direct parents list in each node. Whenever a node would be updated, all the parents and their parents’ full trees would be updated. The Content Compose Service was functioning to create these full trees and storing in the DB. This approach placed all the work on the update operations and the read operations were direct and fast.

Thus the content management system was created and deployed to be consumed by a next js application. The overall target of page load times of less than 1 second were achieved successfully.

(Development team at Infosys: Architect: Jayaram Nettar, Developers: Adwait Mathkari, Karthikeyan Kaliyamoorthy, Debarshi Banerjee, Tuhin Das, Sumit Tiwari)

--

--