How to Develop a Custom CRM using only Low-Code Platforms

Low-code and no-code technologies have enabled everybody to build business software and apps

Building a Custom CRM using Low-code Platforms

In this tutorial we’re going to look at how to build a custom CRM using 2 popular low-code development platforms; Retool and 8base. This will not only give you a great understanding of how Retool can connect to and work with a GraphQL API, but also demonstrate how quickly you can develop a powerful business application using little to no code!‍

Building a Custom CRM Data-model and GraphQL API

We’re going to start by taking care of the backend of our app before moving into the frontend. This is because Retool has a great custom CRM template that we’ll be able to retro-fit to our backend once it’s set up.‍

Empty tables Deals and Touch Points for Custom CRM project
Setting touch points contact medium for Custom CRM project
  1. Confirm that Allow multiple TouchPoints per Deal is checked in the relationship settings and not Allow multiple Deals per TouchPoint.
  2. Check the Deal field is Mandatory validation.
Building a relational data-model for custom CRM
  • stage (type = Switch, Format = Custom, Options = lead/opportunity/customer, Mandatory = true, Default Value = lead)
  • amount (type = Number, Decimal places = 2)
  • deal_name (type = Text, Field Size = 100, Mandatory = true)
  • department (type = Text, Field Size = 100)
  • phoneNumber (type = Text, Field Size = 12)
  • TouchPoints (type = Table)
mutation {
dealCreate(
data: {
deal_name: "Big opportunity at Big.co"
department: "Marketing"
email: "jake@big.co"
amount: 100000.00
stage: "lead"
touchPoints: {
create: [{ contactMedium: "Phone" }, { contactMedium: "Email" }]
}
}
) {
id
deal_name
createdAt
}
}
Create API Token for the custom CRM

Setting up Retool with a GraphQL Resource and Custom CRM template

Retool allows you to connect to a crazy number of data-sources — both APIs and databases. Since 8base exposes a GraphQL endpoint, we’re first going to be adding a GraphQL Resource to our account.‍

Create Retool GraphQL resource for custom CRM
Create Retool app template for flexible CRM

leads Query

The leads query is going to fetch all our deals from the API, taking into consideration what stage we’re looking at as well as whether any filter has been typed in. So in the bottom left of the screen under Queries click on leads. Set the resource as 8base GraphQL Backend and update the query input with the following code snippet.

query($stage: String!, $name: String!) {
dealsList(
filter: {
AND: [{ stage: { equals: $stage } }, { deal_name: { contains: $name } }]
}
) {
items {
id
stage
email
amount
deal_name
createdAt
updatedAt
}
}
}
Update leads graphql query for the custom CRM
Deals table for the custom CRM

touch_points Query

Lets now update our touch_points query. Select the 8base GraphQL Backend resource and then paste in the following query.

query($dealId: ID!) {
touchPointsList(filter: { deal: { id: { equals: $dealId } } }) {
items {
id
createdAt
contactMedium
}
}
}
touch points for custom CRM

create_lead Mutation

Resource: “ 8base GraphQL Backend”

mutation(
$phoneNumber: String!
$department: String!
$deal_name: String!
$email: String!
$amount: Float!
) {
dealCreate(
data: {
phoneNumber: $phoneNumber
department: $department
deal_name: $deal_name
amount: $amount
email: $email
stage: "lead"
}
) {
id
}
}
  • department = {{ newDealDepartment.value }}
  • phoneNumber = {{ newDealPhone.value }}
  • deal_name = {{ newDealName.value }}
  • email = {{ newDealEmail.value }}

upgrade_deal Mutation

Resource: “8base GraphQL Backend”

mutation($stage: String!, $id: ID!) {
dealUpdate(data: { id: $id, stage: $stage }) {
id
stage
email
amount
deal_name
}
}
  • id = {{ leadsTable.selectedRow.data.id }}

downgrade_deal Mutation

Resource: “8base GraphQL Backend”

mutation($stage: String!, $id: ID!) {
dealUpdate(data: { id: $id, stage: $stage }) {
id
stage
email
amount
deal_name
}
}
  • id = {{ leadsTable.selectedRow.data.id }}

set_details Query

Resource: “8base GraphQL Backend”

mutation($email: String, $name: String, $amount: Float, $id: ID!) {
dealUpdate(
data: { id: $id, email: $email, amount: $amount, deal_name: $name }
) {
id
email
amount
deal_name
}
}
  • amount = {{ textinput6.value }}
  • email = {{ textinput7.value }}
  • name = {{ textinput8.value }}

Updating the Custom CRM components

If you’re still here, you’re a trooper! We getting close to the finish line, so hang in there!‍

Image component

The image1 component dynamically generates a random image when given a seed value. Go ahead and update its Image URL value to be https://picsum.photos/id/{{ leadsTable.selectedRow.data.amount % 500 }}/200/200.

Touch Points count

The text13 component counts how many touch points have been made. We can easily display this by updating its Value to:

\# Touch Points#### {{touch_points.data.touchPointsList.items.length}}

Last contact date

For the text14 component, we’re showing the date of the last touch point. This gets accessed from our touch points data and formatted using MomentJS.

Last Contact#### {{ moment(touch_points.data.touchPointsList.items[0].createdAt).format(‘MM/DD/YY’)}}

Next Step and Next Contact

These next two components ( text15, text16) simply suggest the next step by suggesting a different contact medium than was used for the last touch point be made a week after.

Next Contact#### {{ moment(touch_points.data.touchPointsList.items[0].createdAt).add(moment.duration(1, ‘week’)).format(‘MM/DD/YY’)}}Next Step#### {{ touch_points.data.touchPointsList.items[0].contactMedium === ‘email’ ? ‘Phone Call’ : touch_points.data.touchPointsList.items[0].contactMedium === ‘phone’ ? ‘Book Meeting’: ‘Send Email’ }}

Testing the Custom CRM

Loves art, writing, and code.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store