The problem

At Temeda, there was the concept of groups of assets. An asset was essentially a device in the field that we tracked, and a group was a rigid, manually populated group of those assets. The request was to create a system to make these groups more dynamic. This way if a customer wanted to make a group based off of an attribute of an asset (think Make, Model, Year, etc.) they could do so. This would enable more dynamic reporting and decrease the manual effort of maintaining groups. These were aptly named “Dynamic groups.”

The solution

This was certainly one of the more complex projects I’ve worked on. Many parts of the application needed to be updated, and we introduced a brand new GraphQL API into the architecture.

Go GraphQL API

It was decided that a GraphQL API would be used to allow the solution to be agile. Using the introspection calls, we could surface only the fields we wanted to allow users to filter on since some were private fields used by the overall system.

I built the GraphQL API in Go, but customized it quite a bit in order for it to match our system. I created a custom CLI that could analyze the schema of specific tables in SQL Server to generate the models needed for the GraphQL API. I also used attributes in the GraphQL models to add friendly names and a way to control what was displayed in the UI (more on that in a bit).

When a dynamic group was saved, the actual GraphQL query was stored alongside the group in a new field in the SQL Server database. This would be used by our scheduler to update the join tables at specific intervals.

New CI pipeline

This was the first Go project in the environment, and we had discussed utilizing containers more so I opted to make this the first fully containerized piece of our architecture. I set up an Ubuntu server running Docker and configured both Jenkins and Octopus to utilize it for both builds and artifacts.

Hangfire scheduler

We used Hangfire to schedule jobs as needed for various reasons. A new job was defined that would perform the following function every 10 minutes:

  1. Pull the list of dynamic groups, along with the stored query & list of assets.
  2. Run the stored GraphQL query against the GraphQL API to get a list of assets.
  3. If the list didn’t match, update the join tables in the database.

This would ensure that all dynamic groups were current ever 10 minutes at most.

Front end views

To create a good experience for the user, the existing view to manage groups was updated. A checkbox was added to flag the group as dynamic. If true, the view would display a drag and drop UI that allowed user to specify what fields they wanted to filter on, as well as operators (equals, not equals, greater than, etc.) that were specific to the data type of that field.

Once the user had crafted their query, the could preview it to ensure that the correct list of assets was returned.

The result

Once this project was complete, users no longer had to manually keep their groups updated as things changed within their organization. Since groups were utilized heavily in other areas of the application (Ex: Reporting), this dynamism extended to those areas by default as well.