🗄️ Using the CRM Template
806
Getting Started
Hey 👋
Welcome on our Weweb CRM template documentation.
The idea behind this template was to create a rather simple, yet customizable CRM using Weweb (as the frontend) and Xano (as the backend).
Here’s a quick summary video on how this app works 👇
Please know that all the data used in the CRM is fake, except company names that are copyrighted. The person names, emails, and company data are all invented and doesn’t exist.
Also, when you sign up, some data is generated for you so that you can “play” with the template.
⚠️ This data is deleted every Sunday at 01:01:01 PM GMT+2.
Data Structure
The CRM data structure revolves around 5 models:
- user
- company
- contact
- deal
- note
Each of them having their own table and API endpoints.
Here’s a quick video showcasing the data structure and the Xano backend:
ℹ️ We used the REST API in Weweb instead of the Xano plugin most of the time to make the template more pedagogical. Of course, you could use it in your app to go even faster.
To get up to speed quickly, here's a Xano snippet to copy the CRM's backend.
User
The user table is responsible for storing the end users of the app, that means you and me.
It’s composed of these fields:
id: integer
the primary key
created_at: timestamp
storing the record’s creation date and time
name: text
the name of the user
email: text
the email of the user
password: password
the password hash of the user’s password
picture: image
the user’s profile picture
role: text
the user’s role that grants him/her rights
Here’s what it looks like in Xano 👇
Every time a user signs up to the CRM app, his/her data is stored inside this table. And when he/she wants to log in, the app validates the user’s existence and password validity against this table.
Company
The company table stores… companies 😆 (like Airbnb, Google or Weweb 😉)
Every CRM revolves around deals that are tied to a contact and a company. That’s why we have to store companies in a separate table, as some deals can be linked to the same company.
Here are the table fields:
id: integer
the primary key
created_at: timestamp
storing the record’s creation date and time
name: text
the name of the company
domain: text
the web domain of the company’s website
logo: text
the URL of the company’s logo
location: text
the location of the company’s headquarters
industry: text
the company’s industry type
number_of_employees: text
the company’s headcount range
user_id: integer
the foreign-key linking the company to the user’s table
Here’s what it looks like in Xano 👇
As you can see, this table is linked to the user one through a foreign-key so that we’re able to restrict the display of companies (both in Weweb and Xano) to the current user (meaning a user can only see and edit the companies he’s attached to).
Contact
A contact is the person attached to a deal, that’s also part of a company. In the case of a CRM, that’s the person you’re “trying to close” on a deal.
It’s composed of those fields:
id: integer
the primary key
created_at: timestamp
storing the record’s creation date and time
name: text
the name of the contact
picture: image
the profile picture of the contact
email: text
the contact’s email address
job_title: text
the contact’s job title in his/her company
company_id: integer
the foreign key linking the contact to his/her company
user_id: integer
the foreign key linking the contact to the user’s table
Here’s what it looks like in Xano 👇
You can see that the contacts are linked to companies, by storing the API key here, as a contact only have one company, but a company can be linked to multiple contacts.
Deal
Maybe the most important table in the CRM, the deals are all the commercial opportunities that a CRM stores. They’re linked to contacts and companies.
A deal is composed of those fields:
id: integer
the primary key
created_at: timestamp
storing the record’s creation date and time
name: text
the name of the deal
contact_id: integer
the foreign key linking the deal to his/her contact
company_id: integer
the foreign key linking the deal to his/her company
status: text
the current status of the deal that we’ll use to filter deals in the right column in the Weweb kanban (eg: qualified, closing, lost, etc)
description: text
the deal description
order: integer
the order deals are displayed in their column in the Weweb kanban
user_id: integer
the foreign key linking the deal to the user’s table
Here’s what it looks like in Xano 👇
As you can see, a deal is linking both to a contact (and can theoretically have multiple contacts, even if it’s not the case in our data) and a company. That’s why it has 2 foreign keys linking to these tables.
Screens
Signup, Login, Reset and Forgot Password
Signup, login and reset password pages are basically pages containing one form, which on submit sends back the data to Xano to either signup, login or reset the user password:
⚠️ Make sure to send a profile picture. Otherwise, the signup won’t work.
A note on Reset and Forgot Password flow
When a user forgot his/her password, he’ll basically land on the Forgot Password page, where he’ll type his email.
When doing so, it’ll trigger an API call to Xano which will send an email (in this example, through customer.io) to the user which a URL.
When clicking on the email’s URL, the user will land on the Reset Password page concatenated with a querystring variable magic_link
, which will be used inside the Reset Password workflow to sign-in the user without his password (both in Weweb and Xano), then reset his email on Xano-side.
Deals
Here’s a summary of the main elements on this screen 👇
Sidebar
Let’s begin with the first element, which is common to all screens (reusable section), the Sidebar
.
It’s a simple vertical flexbox made of links to other pages and a div which contains the logged-in user’s details:
Kanban
Then, the most important element is the Kanban
. This element is bound the the Deal
collection but also using data from the Contacts
and Companies
collections, as shown here:
The Kanban is made of Stacks that are determined by the status
column inside each Deal.
When moving an item, the Kanban will trigger a workflow which will:
- Update the moved deal status and order by using the Event to and newIndex parameters
- Updating each other deal’s order in the current stack by sending the updated list to Xano
Dropdowns
Then are dropdowns and search bar that are used to filter and search the Deal
collection:
Finally, there is the Add new deal
button which, on click, triggers a workflow that opens a modal (by settings its display variable to true), enabling you to create a deal:
When submitting the form, it’ll POST a new deal to Xano and close the modal by setting the modal’s display variable to false.
Contacts and Companies screens
Datagrid
The only difference with the deals screen is that we replaced the Kanban
with a Datagrid
element:
Also, this element and the dropdown/search are now bound to the Contacts
collection.
When updating or deleting a contact inside the datagrid, it’ll POST or DELETE the contact in Xano and refetch the contacts collection.
For companies, it’s the same, but everything is bound to the Company
collection:
User Management
Workflows
API
💡 It’s actually considered a best practice inside Weweb to store all your API requests inside global workflows that you call from your app’s elements. So that you only have to maintain/edit them once.
First is a folder called API, which is this app API management center:
It references all the Xano’s API endpoints that you can also find here: https://xc0b-vcze-d4we.n7.xano.io/admin/
Every time we’ll need to update or delete a contact, company, deal, etc from the Weweb app, the element triggering the workflow will actually call these global workflows.
Components
Next is a folder called Components that contains all the workflows to trigger the display of elements such as the sidebar or the alerts:
Variables
Deals, Contacts and Companies
In these folders, you’ll find the variables that are used to display specific data from deals, contacts or companies when the UI needs it.
As an example, the selectedDeal variable is used to store the currently clicked on deal that should appear in the modal:
API
API contains the API’s base URL, which is used to construct collections or global workflows URLs without having to always retype the URL in full.
Here’s an example on how it’s used in a collection:
Components
Components variables are used to store the component current state, that you shouldn’t modify directly but use their attached workflows:
Querystring
Querystring variables are used to pass data after the ?
sign in a URL. There’s only one in this project, magic_link, which is used for the reset password: