In this tutorial, we will guide you through the process of building a Legal Document Review & Approval Application using ToolJetDB. This application will simplify the management of legal documents, allowing users to upload, review, and approve documents with a click. By the end of this tutorial, you will have a fully functional application that can handle various operations related to legal document management. This application will be capable of:
- Managing users for document reviewers and approvers.
- Uploading legal documents and associating them with specific users.
- Displaying the status of documents (e.g., approved, pending, rejected).
- Providing an overview of document statistics by user.
- Allowing users to change the status of documents as needed.
Feel free to adjust the structure and functionality of the application to match your exact needs.
Check out this tutorial to learn how to build a fleet management application using ToolJetDB.
Prerequisites:
- ToolJet Account (https://tooljet.com): ToolJet is an open-source, low-code business application builder. Sign up for a free ToolJet cloud account or run ToolJet on your local machine using Docker.
If you prefer to watch the video tutorial instead, check out this link.
Application Overview
To begin, let’s take a look at the main pages we will build for our Legal Document Review & Approval Application:
- Dashboard Page: Provides an overview of document statistics by user, showing how many documents are approved, pending, or rejected.

- Manage Users Page: This page allows admins to manage user accounts, including adding new users.

- Upload Documents Page: Users can upload legal documents associated with their accounts.

- Manage Documents Page: This page displays all uploaded documents along with their statuses, enabling users to approve or reject them.

Step 1: Setting up the Database
You get a blank canvas when you initially launch a new application on ToolJet. We’ll start by adding the Database. Click on ToolJet Rocket Logo at the top-left and then click on Database.
- Click on Create new Table to create a new table. Name it “users”. It will have the following structure:
- id (primary key)
- name
- Add another Table and name it “documents”. It will have the following structure:
- id (primary key)
- user_id (foreign key referencing the Users table (id))
- title
- status
- submitted_at
- approved_at
- rejected_at
Step 2: Creating Pages
Head back to the application after making the database and filling it with some data.
- Navigate to the Pages tab and rename the Home page to “Dashboard”.
- Next, click on the + Button to create a new page. Create three more pages:
- Manage Users
- Upload Documents
- Manage Documents
Design the Header:
- For the header, add a Container Component at the top and stretch it across the page.
- Use appropriate colors and styles according to your needs.
- Drag and Drop a Text Component labeled “Legal Document Review & Approval System”.

- Copy this header and paste it onto the other pages.
Step 3: Building Manage Users Page
Go to the Manage Users Page and add a Table Component. This will be the Users Table. Add a Text Component labeled “Users” to indicate that.
Add User Modal:
- Drag and Drop a Modal Component.
- Change its Title and Trigger Button Label to “Add Users”.
- Feel free to head to the Styles Tab and change the Triggered Button Background Color and Triggered Buttton Text Color to suit your needs.
- Tweak the Modal Size and Height. Set the Modal Size to small and the Modal Height to 200px.
- Add a Button with the label “Submit”. Tweak the colors as needed.
- Let’s add two Text Inputs with labels “Name” and “Email”.

Set up getUsers Query
Expand the Query Panel at the bottom of the screen. Click on the + Add button to create a new query. You can learn more about queries here.
- Rename this query to getUsers.
- Choose ToolJet Database as the Data Source.
- Select the users table for Table Name.
- For the Operation, choose List Rows.
- Enable Run this query on application load in Settings to ensure the query runs whenever the application loads.
Connect the getUsers Query:
In the Table Properties, set the Data field to {{queries.getUsers.data}}. This will connect the data fetched by getUsers to the table.
Set up addUser Query
- Rename this query to addUser.
- Choose ToolJet Database as the Data Source.
- Select the users table for Table Name.
- For the Operation, choose Create Rows.
- Add two Columns, “name” and “email”.
Each column in the users table needs to be linked to the corresponding input field in the Add User Modal.
Use the {{components.<component_name>.value}} syntax in the Key input field to link each column to its respective input component next.
For example:
- Column Name: name
- Input Component Name: textinput2
- Key Value for “name” column:
{{components.textinput2.value}}
Event Handlers help manage triggers and responses in ToolJet. For this Modal, we’ll set up three event handlers:
- A Query Success Event with Action as Show Alert with the message “User added!”. Alert Type as Success.
- A Query Success Event with Action as Close Modal and select current modal to close.
- A Success Event with Action as Run Query and it runs getUsers Query.
Add an On Click Event Handler for the Submit Button that runs the addUser Query.

Step 4: Building Upload Documents Page
Navigate to the Upload Documents Page and add the following components:
- Add a Container Component. In the Styles Tab, set Border Radius to 8 and set Border Color to
#e6e8ebff(Grey). - Insert a Divider with Divider Color
#e6e8ebffto separate the Header section. - Add a Text Component with the label “Upload Documents” as the Header. Customize the styling according to your design requirements.
Let’s add some more Components to the Page:
- Add Text Input Component without any label.
- Add the DropDown (Legacy) Component and remove the default label.
- Add two Text Components that will serve as Labels –
- “Field” against Text Input
- “Name” against Dropdown
- Add a File Picker Component and expand it to fit the rest of the area. In Properties, under Accept file types, enter
{{“pdf/*”}}. This will make sure only PDFs are accepted when documents are uploaded. - Finally, add a Button Component labeled “Submit”. Change styles and colors as needed.
Map getUsers to Name Dropdown
- Click on the DropDown Component.
- Select Option labels and enter
{{queries.getUsers.data.map(i => i.name}}to map getUsers - Click on Option Values and enter
{{queries.getUsers.data.map(i => i.id}}because we need to store ids in the Table.
Let’s add some queries to make sure the uploaded docs are stored correctly.
Set up addDocData Query
- Rename this query to addDocData.
- Choose ToolJet Database as the Data Source.
- Select the documents table for Table Name.
- For the Operation, choose Create Rows.
- Add four Columns:
- “User_id” with key –
{{components.dropdownlegacy1.value}} - “title” with key –
{{components.textinput1.value}} - “status” with key – “Pending”
- “submitted_at” with Key –
{{moment.format()}}
- “User_id” with key –
ToolJet supports moment.js library that can parse, validate, manipulate, and display dates and times in JavaScript accurately. We will use it to get the correct time of submission.
- Add two Event Handlers:
- A Query Success Event and Action as Show Alert with the message “Data saved!”. Alert Type as Success.
- A Query Success Event with Action as Run Query and it runs addDoctoS3 Query.
Set up addDoctoS3 Query
Make sure to connect S3 as a Data source before continuing. Add a bucket in your AWS Regions as well.
- Rename this query to addDoctoS3.
- Under AWS S3, choose s3 as the Data Source.
- For the Operation, choose Upload object.
- Add the name of the bucket you’ve made in AWS to Bucket.
- For Key we will add the id of the latest item we’ve stored. Add
{{"doc" + “-” + queries.addDoPata.data[0].Id}}to do that. - Enter
{{components.filepickerl.file[0].type}}into Content type as we will get that data from filepicker itself. - Enter
{{components.filepickerl.file[0].dataURL}}into Upload Data as the data is from filepicker component too. - Let the Encoding be “base64”.
- Add an Event Handler to show an alert that the document has been saved.
Add an Event Handler In the Submit Button. This will run the addDoctoS3 Query.

Next, we are going to build the Manage Documents Page. It is the most important page as it allows users to view, approve, or reject documents.
Step 5: Building Manage Documents Page
- Add a Table Component and a Container Component.
- Add a Divider in the container to separate the Header from the rest of the components. Change its color to fit your needs.
- Add a Text Component with the label “Document Details” and style it.
- We will add another Text Component in the Container. Under Data in Properties, Click on Markdown and add the following text:
**Name** :
**Email** :
**Document** :
**Status** :
**Submitted_at** :
- Change the line height to 3 and Size to 15.
- Add Three Buttons with the following label:
- View Document
- Approve
- Reject
Feel free to stylize the Buttons to fit your requirements.
The UI for this page is now complete.

Set up getDocData Query
- Rename this query to getDocData.
- Choose ToolJet Database as the Data Source.
- Select the documents table for Table Name.
- For the Operation, choose Join Tables.
- Now in Joining Tables, choose users.
- In On under Selected Table, choose “user_id” and = “id” in the Joining Table. This is because we have a foreign key relationship between the two tables with these columns.
- At the bottom of the Query Setup Page, you can select the columns you want to view. In Select, All Columns are currently selected for both tables. For users, we don’t want id, and for documents, we don’t want approved_at and rejected_at.
- Click on the Table Component, and in the Table Properties, set the Data field to
{{queries.getDocData.data.result}}. This will connect the data fetched by getDocData to the table. - We will remove unnecessary columns from the Table as we don’t want them in view. Remove the following using the Columns Field under Properties:
- document_id
- users_email
- document_submitted_at
- Make sure to add Sort for the “documents.id” and set it to “Ascending”.
- Finally, enable Run this query on application load in Settings to ensure the query runs whenever the application loads.
Look at the first query and set the Default Selected Row to it. For us, the first query has a document id 5. So we’ll add {{{“documents_id”: 5}}} in the Default Selected Row.

Now we will take the data from the selected row and add them to the Data property of the Text Component.
**Name** : {{components.table1.selectedRow.users_name}}
**Email** : {{components.table1.selectedRow.users_email}}
**Document** : {{components.tabte1.selectedRow.documents_title}}
**Status** : {{components.table1.selectedRow.documents_status}}
**Submitted_at**: {{moment(components.table1.selectedRow.documents_submitted_at).format('YYYY-MM-DD HH:mm:ss')}}
Set up getDocFromS3 Query
- Rename this query to getDocFromS3.
- Under AWS S3, choose s3 as the Data Source.
- For the Operation, choose Signed url for download.
- Add the name of the bucket you’ve made in AWS to Bucket. Make sure it’s the same one as addDocToS3 Query.
- We need the same key as when we were submitting the document so add
{{"doc" + components.table1.selectedRow.documents_id}}.
Select the View Document Button and add two Event Handlers:
- An On Click Event with Action as Run Query and it runs getDocFromS3 Query.
- An On Click Event with Action as Open Webpage and URL:
{{queries.getDocFromS3.data.url}}.
Set up approveDoc Query
- Rename this query to approveDoc.
- Choose ToolJet Database as the Data Source.
- Select the documents table for Table Name.
- For the Operation, choose Update Rows.
- Add a Filter – “id” “equals” “
{{components.table1.selectedRow.documents_id}} - Let’s select the columns we need to update with Keys:
- “status” with Key – “Approved”
- “approved_at” with Key –
{{moment().format()}}
- Head to Settings, and add two Event Handlers:
- A Query Success Event with Action as Show Alert with the message “Document approved!”. Alert Type as Success.
- A Query Success Event with Action as Close Modal and select current modal to close.
- A Success Event with Action as Run Query and it runs getDocData Query.
- To indicate that data is being fetched, we will add a Loader. In the Table, under Additional Actions, add the getDocData query
{{queries.getDocData.isLoading}}to the active Loading state. This will display a loader while data is being retrieved. - Add a Loader
{{queries.getDocData.isLoading}}for the Document Details Text Component as well. - Finally, connect the Query to the Approve Button by adding an Event Handler in it that runs the approveDoc Query.
Set up rejectDoc Query
Click on the Duplicate Query Button against the approveDoc Query. As most data will be the same, it’s easier just to duplicate the Query.
- Rename this query to rejectDoc.
- Under Columns, change the key against “status” to “Rejected” and switch the approved_at Column to rejected_at.
- Edit the Query Success Event Handler with the message “Document rejected”.
- Connect the Query to the Reject Button by adding an Event Handler in it that runs the rejectDoc Query.
Step 6: Building the Dashboard Page
On the Dashboard Page, configure the following text elements:
- Add a Text Component labeled “Dashboard” for the Heading.
- Similarly, include a subheading with the text “Get a quick overview of your users, their documents & details” Apply appropriate styling to match your application’s design.
We will use HTML in the Analytics Boxes shown at the Top.
- Add a Text Component and choose HTML. Write the following HTML in the Data field:
<strong>Total Documents</strong> </br> <small 5 </small>
We are adding “5” as a placeholder and will add a query for this data later on.
- Make the text center aligned.
- Change the color of the text to Blue and set the background color as white. Set the border to Blue as well.
- Copy the Text Component. Make two copies of it.
One will have the text “Approved” and the other will have “Rejected”. - Change the colors of these components accordingly.
Finally, add a Tab Component, This will have 3 Tabs with Tables in it.
- Add a Table Component in one of the Tabs. Change its style to fit your needs.
- Copy the Table into the other two Tabs.
- Change the Tab Names. In Properties, under Tabs, change the names to “Overview”, “Status by Users”, and “Document count by Users”.
![User Interface of Dashboard Page]()
Now we’ll add a Query for Overview Tab.
Set up getOverview Query
- Rename this query to getOverview.
- Choose ToolJet Database as the Data Source.
- Select the documents table for Table Name.
- For the Operation, choose Join Tables.
- Now in Joining Tables, choose users.
- In Select, hide the “id” column from the users table and both the “id” and “user_id” columns from the documents table.
- Finally, connect the query to the Overview Table by adding
{{queries.getOverview.data.result}}to the Data field of the Table.
Let’s work on the Status by Users Tab next.
We already copied a Table from another tab. Now we need a Dropdown for selecting users for this Tab.
- Go to the Upload Documents Page and copy the Dropdown Component.
- Paste it into the Status by Users Tab of the Dashboard Page.
- Add a label “Name” for this Dropdown. Resize it to fit your needs.
Set up getStatusByUsers Query
- Rename this query to getStatusByUsers.
- Choose ToolJet Database as the Data Source.
- Select the documents table for Table Name.
- For the Operation, choose Join Tables.
- Now in Joining Tables, choose users.
- In Aggregate, Select Count and Select “status” Column.
- In Group by, for documents Table, choose “status”.
- Make sure to add a Filter, Where “users.id” equals
{{components.dropdownlegacy1.value}} - Add an Event Handler in this Dropdown Component – An On Select Event with Action Run Query that runs getStatusByUsers Query.
- Add a Loader. In the Table for this Tab, under Additional Actions, add the getStatusByUsers query as
{{queries.getStatusByUsers.isLoading}}to the active Loading state. This will display a loader while data is being retrieved. - Connect the query to the Status by Users Table by adding
{{queries.getStatusByUsers.data.result}}to the Data field of the Table.

Set up getDocCountByUsers Query
For the Document count by Users Tab, we’ll duplicate the getStatusByUsers Query.
- Rename it to getDocCountByUsers,
- Remove the Filter.
- In Aggregate, change the “status” Column to “id” from the Documents Table.
- In Group By, remove the “status” from documents. Add “name” and “email’ in users.
- Connect the query to the Document Count by Users Table by adding
{{queries.getDocCountByUsers.data.result}}to the Data field of the Table.

Finally, let’s add a RunJS Query to show the correct data for each of the three Analytics Boxes.
Set up getDocCount Query
- Expand the Query Builder and click on +.
- Choose Run JavaScript code,
- Rename this query to getDocCount.
- Click on the small code button in the bottom right corner of Code Editor to expand the editor.
Add the following code:
await queries.getOverview.run();
let value = queries.getOverview.getData();
function processDocumentData(data) {
let total = 0;
let approved = 0;
let rejected = 0;
data.result.forEach(doc => {
total++;
if (doc.documents_status == "Approved") {
approved++;
} else if (doc.documents_status == “Rejected”) {
rejected++;
} });
return { total, approved, rejected } ;
}
return processDocumentData(value)
The final HTML code for Total Documents is as follows:
<strong>Total Documents</strong> </br> <small {{queries.getDocCount.data.total}} </small>
Repeat the same for the other two Text Components adding the approved count and rejected count respectively.
The final HTML code for Approved:
<strong>Total Documents</strong> </br> <small {{queries.getDocCount.data.approved}} </small>
The final HTML code for Rejected:
<strong>Total Documents</strong> </br> <small {{queries.getDocCount.data.rejected}} </small>
Final Application Preview
The completed Legal Document Review & Approval Application provides a user-friendly interface where admins can manage users and documents. The Dashboard Page offers a quick overview of document statistics, displaying total documents, approved documents, and rejected documents in a clear table format.
How the Application Works
Users can navigate to the Manage Users Page to add or modify user accounts easily. The Upload Documents Page allows users to upload legal documents associated with their accounts, ensuring that each document is linked to the correct user. Once uploaded, documents can be viewed and their statuses changed on the Manage Documents Page, where users can approve or reject submissions as necessary.

This application simplifies the process of document management, making it easy for users to track submissions, review statuses, and maintain an organized workflow.
Conclusion
Congratulations! You have successfully built a Legal Document Review & Approval Application using ToolJetDB. Feel free to expand upon this by adding more features or integrating additional services as needed. If you have any doubts or feedback, feel free to share your thoughts in our Slack Community.
The post Building a Legal Document Review & Approval Application with ToolJetDB appeared first on ToolJet.
