Inventory tracking web application written in JavaScript.
Table of Contents
3PL-ify is an inventory tracking web application built for a logistics company. The server application supports CRUD operations on inventory and warehouses, as well as the allocation of inventory to warehouses.
My focus in developing this application was a high degree of modularity, to support the addition of features in the future (e.g., extending the data model and API to include Vendors, Shipments and Metadata).
This project also includes a basic client application to demo the functionality of the server application.
- Create an inventory item
- View a list of all inventory items
- View a specific inventory item
- Edit an inventory item
- Delete an inventory item
- Create a warehouse
- View a list of all warehouses
- View a specific warehouse
- Edit a warehouse
- Delete a warehouse
Stock Levels allow you to allocate items of inventory to specific warehouses. A StockLevel represent a number of units of a specific item in a specific warehouse.
- Create a StockLevel
- Create an adjustment to the inventory level for an existing StockLevel
- Set the inventory level for an existing StockLevel
This application is written entirely in JavaScript.
- Express as the framework for the server application
- PostgreSQL as the relational database management system
- Sequelize as the ORM tool for modelling and interacting with the PostgreSQL database
- React as the library for the intreactive user interface
- Create React App to streamline the configuration, transpilation and building of the React application
- React Bootstrap for pre-built, Bootstrap-styled React components
- Axios as an HTTP client
You will need the following installed in your environment:
Create the PostgreSQL database (commands may differ by operating system):
psql
CREATE DATABASE _3plify_inventory;
\q
Create a .env
file in the server
directory with your PostgreSQL database local connection URI (may differ by local configuration):
Make sure you are in the root of the project directory.
# Example connection string; may differ by local configuration
echo "PG_URI=postgres://localhost:5432/_3plify_inventory" > server/.env
Change into the server
directory, install dependencies and seed the database with sample data:
cd server
npm install
npm run seed
Change into the client
directory and install dependencies:
cd ../client
npm install
In one terminal, start the development server:
cd server
npm start
In a separate terminal, start the client application development server:
cd client
npm start
Open http://localhost:3000 to view it in your browser.
Base URL (dev server): http://localhost:3001/api
Creates a new inventory item
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
name |
string | yes | none | name of the item |
minStock |
integer | yes | 0 | minimum stock level (at least 0) |
vendorName |
string | yes | none | name of vendor |
Status: 201 Created
{
"newItem": {
"id": 7,
"name": "Circuit Amptek",
"minStock": 200,
"vendorName": "Snow Devil",
"updatedAt": "2022-01-19T22:28:59.884Z",
"createdAt": "2022-01-19T22:28:59.884Z"
}
}
Retrieves a list of all inventory items
Status: 200 OK
{
"items": [
{
"id": 1,
"name": "Angus Magtek",
"vendorName": "Snow Devil",
"minStock": 150,
"createdAt": "2022-01-19T21:04:34.879Z",
"updatedAt": "2022-01-19T21:04:34.879Z"
},
{
"id": 2,
"name": "Circuit Amptek",
"vendorName": "Snow Devil",
"minStock": 300,
"createdAt": "2022-01-19T21:04:34.889Z",
"updatedAt": "2022-01-19T21:04:34.889Z"
},
{
"id": 3,
"name": "Easy Livin",
"vendorName": "Snow Devil",
"minStock": 500,
"createdAt": "2022-01-19T21:04:34.911Z",
"updatedAt": "2022-01-19T21:04:34.911Z"
}
]
}
Retrieves a single inventory item
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
itemId |
integer | yes | none | id of the item you are querying |
Status: 200 OK
{
"item": {
"id": 1,
"name": "Angus Magtek",
"vendorName": "Snow Devil",
"minStock": 150,
"createdAt": "2022-01-19T21:04:34.879Z",
"updatedAt": "2022-01-19T21:04:34.879Z"
}
}
Updates an entire inventory item record
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
itemId |
integer | yes | none | id of the item you are updating |
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
name |
string | yes | none | name of the item |
minStock |
integer | yes | 0 | minimum stock level (at least 0) |
vendorName |
string | yes | none | name of vendor |
Status: 204 No Content
Deletes an inventory item
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
itemId |
integer | yes | none | id of the item you are deleting |
Status: 204 No Content
Creates a new warehouse
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
name |
string | yes | none | name of the warehouse |
adddressLine1 |
string | yes | none | street address |
adddressLine2 |
string | no | none | unit #, suite #, etc. |
city |
string | yes | none | city of the warehouse |
province |
string | yes | none | province of the warehouse (official 2-letter abbreviation) |
postalCode |
string | yes | none | postal code of the warehouse, including space between (e.g., A1B 2C3) |
Status: 201 Created
{
"newWarehouse": {
"id": 5,
"name": "Toronto North",
"addressLine1": "123 Warehouse Lane",
"addressLine2": "Suite 5A",
"city": "Toronto",
"province": "ON",
"postalCode": "A1B 2C3",
"updatedAt": "2022-01-19T22:40:31.182Z",
"createdAt": "2022-01-19T22:40:31.182Z"
}
}
Retrieves a list of all warehouses
Status: 200 OK
{
"warehouses": [
{
"id": 1,
"name": "Ottawa Central",
"addressLine1": "123 Entrepreneur Lane",
"addressLine2": "Unit 2A",
"city": "Ottawa",
"province": "ON",
"postalCode": "K1G 2C3",
"createdAt": "2022-01-19T20:04:15.725Z",
"updatedAt": "2022-01-19T20:04:15.725Z"
},
{
"id": 2,
"name": "Ottawa East",
"addressLine1": "405 Rebel Road",
"addressLine2": "Suite 105",
"city": "Ottawa",
"province": "ON",
"postalCode": "K2P 3B5",
"createdAt": "2022-01-19T20:04:15.727Z",
"updatedAt": "2022-01-19T20:04:15.727Z"
},
{
"id": 3,
"name": "Big Warehouse",
"addressLine1": "370 SMB Square",
"addressLine2": null,
"city": "Ottawa",
"province": "ON",
"postalCode": "K1P 6D6",
"createdAt": "2022-01-19T20:04:15.728Z",
"updatedAt": "2022-01-19T20:04:15.728Z"
}
]
}
Retrieves a single warehouse
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
warehouseId |
integer | yes | none | id of the warehouse you are querying |
Status: 200 OK
{
"warehouse": {
"id": 5,
"name": "Toronto North",
"addressLine1": "123 Warehouse Lane",
"addressLine2": "Suite 5A",
"city": "Toronto",
"province": "ON",
"postalCode": "A1B 2C3",
"createdAt": "2022-01-19T22:40:31.182Z",
"updatedAt": "2022-01-19T22:40:31.182Z"
}
}
Updates an entire warehouse record
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
warehouseId |
integer | yes | none | id of the warehouse you are updating |
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
name |
string | yes | none | name of the warehouse |
adddressLine1 |
string | yes | none | street address |
adddressLine2 |
string | no | none | unit #, suite #, etc. |
city |
string | yes | none | city of the warehouse |
province |
string | yes | none | province of the warehouse (official 2-letter abbreviation) |
postalCode |
string | yes | none | postal code of the warehouse, including space between (e.g., A1B 2C3) |
Status: 204 No Content
Deletes a warehouse
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
warehouseId |
integer | yes | none | id of the warehouse you are deleting |
Status: 204 No Content
Creates a new stockLevel (number of units of a given item in a given warehouse)
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
itemId |
integer | yes | none | id of the associated item |
warehouseId |
integer | yes | none | id of the associated warehouse |
units |
integer | yes | none | number of units of item in warehouse (at least 0) |
Status: 201 Created
{
"stockLevel": {
"id": 8,
"itemId": 2,
"warehouseId": 4,
"units": 100,
"updatedAt": "2022-01-19T22:48:26.161Z",
"createdAt": "2022-01-19T22:48:26.161Z"
}
}
Get stockLevels for a given item
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
itemId |
integer | yes | none | id of the item associated with the stockLevels you are querying |
Status: 200 OK
{
"stockLevels": [
{
"id": 2,
"units": 200,
"createdAt": "2022-01-19T21:04:34.944Z",
"updatedAt": "2022-01-19T21:04:34.944Z",
"itemId": 1,
"warehouseId": 2,
"warehouse": {
"id": 2,
"name": "Ottawa East"
}
},
{
"id": 1,
"units": 100,
"createdAt": "2022-01-19T21:04:34.940Z",
"updatedAt": "2022-01-19T21:20:38.483Z",
"itemId": 1,
"warehouseId": 1,
"warehouse": {
"id": 1,
"name": "Ottawa Central"
}
}
]
}
Delete a stockLevel
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
itemId |
integer | yes | none | id of the item associated with the stockLevels you are querying |
warehouseId |
integer | yes | none | id of the warehouse associated with the stockLevels you are querying |
Status: 204 No Content
Creates an adjustment to the number of units associated with an existing stockLevel
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
itemId |
integer | yes | none | id of the item associated with the stockLevels you are adjusting |
warehouseId |
integer | yes | none | id of the warehouse associated with the stockLevels you are adjusting |
adjustment |
integer | yes | none | number of units by which to adjust the stockLevel; stockLevel must be at least 0 after adjustment |
Status: 201 Created
{
"stockLevel": {
"id": 1,
"units": 1400,
"createdAt": "2022-01-19T21:04:34.940Z",
"updatedAt": "2022-01-19T21:18:28.472Z",
"itemId": 1,
"warehouseId": 1
}
}
Sets the number of units associated with an existing stockLevel
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
itemId |
integer | yes | none | id of the item associated with the stockLevels you setting |
warehouseId |
integer | yes | none | id of the warehouse associated with the stockLevels you are setting |
units |
integer | yes | none | number of units of item in warehouse (at least 0) |
Status: 201 Created
{
"stockLevel": {
"id": 1,
"units": 200,
"createdAt": "2022-01-19T21:04:34.940Z",
"updatedAt": "2022-01-19T21:20:38.483Z",
"itemId": 1,
"warehouseId": 1
}
}