Inventory Management Quick Start

Inventory visibility is critical for suppliers to manage inventories in their channels. A supplier that fails to do so risks high or low inventory stock events, missed sales opportunities, and customer disappointment. Knowing how much inventory is in a channel helps to mitigate these risks.

In this Quick Start, we will deploy a sample inventory channel involving a single Distribution Center and two retailers.

By the end of the Quick Start you will have:

  • Created a Universal Application (uni) with a pre-defined data model
  • Defined a channel of partners and created them as parties in our uni
  • Used GraphQL queries and mutations to both read from and write to our inventory
  • [Optionally] Set up block notifications to have visibility when updates are made to the uni's data

Pre-requisites

This Quick Start uses the Vendia share-cli, a Command Line Interface (CLI) for creating and managing unis. We will be using the share-cli to deploy and manage our product catalog.

Command Line Installation

The share-cli can be installed using the NodeJS Node Package Manager(NPM).

To install the CLI globally, run the following command:

npm install --global @vendia/share-cli

NOTE: You can also install the Vendia CLI inside of a project (instead of globally).

For more information, please visit the @vendia/share-cli NPM package page or view the CLI commands list.

Register for Vendia Share

You will need to have a valid Vendia Share user in order to deploy this Quick Start. Please sign up for Vendia Share if you have not already done so.

Step 1 - Prepare the Deployment Files for the Uni

In this Quick Start, we have provided sample files including a data model for your use that describes product inventory data.

Save the Quick Start Files

The files listed below should be saved to your computer. For simplicity, save them all to the same directory.

Sample registration file - save as registration.json

The registration.json file defines the uni name, location of the schema file, and the participants in the uni. Optionally, it can also include the location of an initState file that seeds the uni with data when it is created.

{
  "name": "test-inventory",
  "schema": "schema.json",
  "nodes": [
    {
      "name": "DistributionCenter",
      "userId": "me@domain.com",
      "region": "us-east-2"
    },
    {
      "name": "Retailer1",
      "userId": "me@domain.com",
      "region": "us-west-2"
    },
    {
      "name": "Retailer2",
      "userId": "me@domain.com",
      "region": "us-west-2"
    }
  ]
}

NOTE: You will need to provide your Vendia Share userId when defining your node.

ANOTHER NOTE: Pick a unique name for your Uni that begins with test- - by default all Unis share a common namespace so here is your chance to get creative.

ONE MORE NOTE: You can deploy your nodes to many different regions spread across the globe. In this example, we are deploying three separate nodes to three separate AWS regions. Each node will have a consistent view of inventory data. Please review the list of supported cloud platforms and regions.

Sample schema file - save as schema.json

The schema is used to define the shape of the inventory data held in your uni. Vendia Share will take this data model and create the API and GraphQL queries used for interacting with our inventory data.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://vendia.net/schemas/demos/inventory-management-system.json",
  "title": "Inventory Management System",
  "description": "Store inventory data",
  "type": "object",
  "properties": {
    "InventoryItem": {
      "description": "Inventory items",
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "itemName": {
            "description": "Item name",
            "type": "string"
          },
          "itemNumber": {
            "description": "Item number",
            "type": "string"
          },
          "quantity": {
            "description": "Available quanitity of item",
            "type": "integer"
          },
          "tags": {
            "description": "Tags associated with item",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}

Step 2 - Command Line Deployment

Once the files are saved, deploy the Uni using the share-cli.

If not already logged in to the share service do so by running share login:

share login

The share uni create command can be used to deploy our Uni.

share uni create --config registration.json

Check on Uni Status

The Uni deployment will take approximately 4 minutes. The status of the Uni deployment can be viewed by running the share get command.

NOTE: Your uni name should differ from the example. Set the value of the --uni argument accordingly to match the Name property in registration.json.

 % share get --uni test-inventory
Getting test-inventory info...
┌─────────────────────┐
│   Uni Information   │
└─────────────────────┘
Uni Name:    test-inventory.unis.vendia.net
Uni Status:  PENDING_REGISTRATION
Node Count:  3
Nodes Info:
├─ ⬢ DistributionCenter
│  ├─ name: DistributionCenter
│  ├─ status: DEPLOYING
│  └─ resources:
│     ├─ graphqlurl
│     ├─ graphqlapikey
│     ├─ sqs
│     └─ s3bucketarn
├─ ⬢ Retailer1
│  ├─ name: Retailer1
│  ├─ status: DEPLOYING
│  └─ resources:
│     ├─ graphqlurl
│     ├─ graphqlapikey
│     ├─ sqs
│     └─ s3bucketarn
└─ ⬢ Retailer2
   ├─ name: Retailer2
   ├─ status: DEPLOYING
   └─ resources:
      ├─ graphqlurl
      ├─ graphqlapikey
      ├─ sqs
      └─ s3bucketarn

To display schema & initial state, use the --json flag. Example: "share get test-inventory.unis.vendia.net --json"

When the uni status changes to RUNNING we can begin interacting with it.

Step 3 - Query Inventory Data

Now that our uni is in a RUNNING state know that each node - DistributionCenter, Retailer1, and Retailer2 - is available for each party to use.

The easiest way to interact with data in our inventory uni is to use the built-in GraphQL Explorer provided by the Vendia Share web interface. Click on the name of the uni you created. Each node in a uni has its own GraphQL Explorer. Let's use the DistributionCenter GraphQL Explorer.

Uni Dashboard Image

NOTE: You are not constrained to running GraphQL queries from the provided GraphQL Explorer. You can query nodes using the graphqlurl and graphqlapikey specified on your uni's settings page with the programming language of your choice.

Run Your First Query

The GraphQL Explorer window will be pre-populated with an example query. Delete this query and replace it with the query below to view your inventory. Run the query by pressing the play button.

query listItems {
  listInventoryItems {
    InventoryItems {
      id
      itemName
      itemNumber
      quantity
      tags
    }
  }
}

The inventory list should be empty. Our first order of business will be to add initial inventory data.

Step 4 - Create New Entries in the Inventory

Now that we have queried our data, let's go ahead and add new items to our inventory. Copy and paste the text below and execute each of the addWidget mutations from the DistributionCenter GraphQL Explorer.

mutation addWidget1 {
  addInventoryItem_async(
    input: {
      itemName: "Widget 1",
      itemNumber: "w123-a",
      quantity: 1000,
      tags: [
        "new-release",
        "stainless-steel"
      ]
    }
  ) {
    error
    result {
      id
      submission_time
    }
  }
}

mutation addWidget2 {
  addInventoryItem_async(
    input: {
      itemName: "Widget 2",
      itemNumber: "w124-b",
      quantity: 475,
      tags: [
        "low-stock",
        "reorder"
      ]
    }
  ) {
    error
    result {
      id
      submission_time
    }
  }
}

mutation addWidget3 {
  addInventoryItem_async(
    input: {
      itemName: "Widget 3",
      itemNumber: "w125-a",
      quantity: 1378
    }
  ) {
    error
    result {
      id
      submission_time
    }
  }
}
Image of New Inventory Mutations

If we run the listItems query we will see the new products we added to the inventory.

Image of New Product in Catalog

Step 5 - Query Inventory Data from Retailer2

Now that we have data in our uni, let's query it from another node. Remember - our uni presents a consistent view of data across all nodes in the uni. Let's go back to our uni's home page and select the GraphQL Explorer for Retailer2. Members of our supply chain would want to know how much stock is available from a distribution center if their on-hand inventory is approaching a low level.

We can use filtered or unfiltered queries to drill down into our inventory data.

Filtered Query of Inventory Data

We can search for inventory and filter our results. Let's say that Retailer2 knows their in-store quantity of Widget 1 is low and they need a shipment from the Distribution Center. The following filtered query could be used to display the attributes of Widget 1 inventory stock.

query widget1Query {
  listInventoryItems(
    filter: {
      itemName: {
        eq: "Widget 1"
      }
    }
  ) {
    InventoryItems {
      id
      itemName
      itemNumber
      quantity
      tags
    }
  }
}
Image of Filtered Query

NOTE: Make note of the id value. We're going to need it when we update the quantity for Widget 1.

Unfiltered Query of Inventory Data

If Retailer2 wanted to view the id, itemName, itemNumber, quantity, and tags attributes of all inventory stock the following unfiltered query could be used.

query allInventoryQuery {
  listInventoryItems {
    InventoryItems {
      id
      itemName
      itemNumber
      quantity
      tags
    }
  }
}
Image of Unfiltered Query

Step 6 - Update Inventory Data

Let's continue our scenario of Retailer2 having low quantities of Widget 1 on-hand. They would like to have an addition 200 Widget 1s. The query below is used to update the available quantity of Widget 1 from 1000 to 800.

mutation updateQuantityWidget1 {
  updateInventoryItem_async(
    id: "f45e4ad7-60d8-11eb-ba0f-bf56fd5edaf8",
    input: {
      itemName: "Widget 1",
      itemNumber: "w123-a",
      quantity: 800,
      tags: [
        "new-release",
        "stainless-steel"
      ]
    }
  ) {
    result {
      id
      submission_time
      tx_id
    }
    error
  }
}
Image of Widget 1 Quantity Update

NOTE: The id value used in my query will be different than the one you use. Adjust your query accordingly.

To demonstrate how our update (write) is visible to all nodes let's go to the GraphQL Explorer on Retailer1. We can run the same widget1Query query we ran earlier.

query widget1Query {
  listInventoryItems(
    filter: {
      itemName: {
        eq: "Widget 1"
      }
    }
  ) {
    InventoryItems {
      id
      itemName
      itemNumber
      quantity
      tags
    }
  }
}
Image of Widget 1 Query Retailer1

Step 7 [Optional] - Configure DistributionCenter to Receive Block Notifications

The following exercise is completely optional

Each node in a uni can be configured to emit notifications when a new block is created. This block notification can be sent to a number of outbound integrations. In this Quick Start, we'll configure our DistributionCenter to send notifications to a AWS Lambda function. We'll show how such a notification can be used to take further action in the inventory channel - perhaps automatically triggering an order with a product manufacturer when an inventory quantity reaches a specified threshold.

NOTE: This example uses the AWS Command Line Interface version 2. Installation and configuration instructions are outside the bounds of this Quick Start.

ANOTHER NOTE: The AWS Lambda function receiving the block notification must be deployed to the same AWS region as our node.

Determine the ARN of the DistributionCenter SNS Topic

Notifications from your node are emitted from a provisioned AWS SNS topic. SNS is a pub/sub messaging service. We can determine this value by looking at the uni's settings page. In this example, we need the Notification SNS Topic ARN value from our DistributionCenter node. The ARN will have the following format:

arn:aws:sns:aws-region:your-node-aws-account-number:node-sns-topic-name

Image of Distribution Center Node Settings

Create and Configure a AWS Lambda Function to Capture the Block Notification

We will create a Python 3.8 function with default values. The following code will capture the blockId of our newly created block. I'll refer to the function as lambda-block-function-in-your-account moving forward.

import json

def lambda_handler(event, context):
    for record in event['Records']:
        block_report = json.loads(record['Sns']['Message'])
        print(f'Here is where you could issue a getBlock query against blockId {block_report["BlockId"]} to get more detail, including the mutation that was run.')

Attach a Resource-based Policy

The function lambda-block-function-in-your-account will need to allow the SNS Topic in your DistributionCenter node to trigger it. The following aws command can be used.

NOTE: There are placeholder values in this policy. Please adjust accordingly.

% aws lambda add-permission --function-name lambda-block-function-in-your-account \
--source-arn arn:aws:sns:aws-region:your-node-aws-account-number:node-sns-topic-name \
--statement-id lambda-block-notification --action "lambda:InvokeFunction" \
--principal sns.amazonaws.com  \
--query Statement --output text \
--region aws-region [--profile aws-profile-name]
{"Sid":"lambda-block-notification","Effect":"Allow","Principal":{"Service":"sns.amazonaws.com"},"Action":"lambda:InvokeFunction","Resource":"arn:aws:lambda:aws-region:your-aws-account-number:function:lambda-block-function-in-your-account","Condition":{"ArnLike":{"AWS:SourceArn":"arn:aws:sns:aws-region:your-node-aws-account-number:node-sns-topic-name"}}}
Image of Lambda Resource Policy

Subscribe Function to DistributionCenter SNS Topic

The following representative aws command can be used.

% aws sns subscribe --protocol lambda \
--topic-arn arn:aws:sns:aws-region:your-node-aws-account-number:node-sns-topic-name \
--notification-endpoint arn:aws:lambda:aws-region:your-aws-account-number:function:lambda-block-function-in-your-account \
--region aws-region [--profile aws-profile-name]
{
    "SubscriptionArn": "long-subscription-arn"
}

Query the DistributionCenter Node Settings

Each node has settings that are associated with it. One of the settings we have is the aws_blockReportLambdas. This is the one we'll update for this Quick Start.

NOTE: It is important to get all of the settings from your DistributionCenter GraphQL Explorer. When we update settings we will overwrite any existing settings so take care to record any existing values.

query getSettings {
  get_Settings {
    aws_DataDogMonitoring {
      ddApiKey
      ddExternalId
      ddLogEndpoint
      ddSendLogs
    }
    aws_LambdaIngressAccounts
    aws_S3ReadAccounts
    aws_SQSIngressAccounts
    aws_blockReportFirehoses
    aws_blockReportLambdas
    aws_blockReportSQSQueues
    blockReportEmails
    blockReportWebhooks
    aws_deadLetterLambdas
    aws_deadLetterSQSQueues
    deadLetterEmails
    deadLetterWebhooks
    apiSettings {
      apiKeys {
        usagePlan {
          quotaSettings {
            limit
            offset
            period
          }
          throttleSettings {
            burstLimit
            rateLimit
          }
        }
        value
      }
      auth {
        allowedAccounts
        authorizerArn
        authorizerType
      }
    }
  }
}
Image of Null Distribution Center Node Settings

Update and Verify the DistributionCenter aws_blockReportLambdas Node Setting

The following query can be used to update the node's aws_blockReportLambdas setting. Use the Lambda function ARN of the function you created earlier.

NOTE: Adjust the query to accomodate any additional settings you already have applied.

mutation update_blockReportLambdas {
  update_Settings_async(input: {
        aws_blockReportLambdas: [
            "arn:aws:lambda:aws-region:your-aws-account-number:function:lambda-block-function-in-your-account"
        ]
    }) {
        error
        result {
          id
          tx_id
        }
  }
}
Image of Updating Distribution Center Node Settings

Let's run the getSettings query we defined above and confirm our aws_blockReportLambdas setting is present with the proper function ARN.

query getSettings {
  get_Settings {
    aws_DataDogMonitoring {
      ddApiKey
      ddExternalId
      ddLogEndpoint
      ddSendLogs
    }
    aws_LambdaIngressAccounts
    aws_S3ReadAccounts
    aws_SQSIngressAccounts
    aws_blockReportFirehoses
    aws_blockReportLambdas
    aws_blockReportSQSQueues
    blockReportEmails
    blockReportWebhooks
    aws_deadLetterLambdas
    aws_deadLetterSQSQueues
    deadLetterEmails
    deadLetterWebhooks
    apiSettings {
      apiKeys {
        usagePlan {
          quotaSettings {
            limit
            offset
            period
          }
          throttleSettings {
            burstLimit
            rateLimit
          }
        }
        value
      }
      auth {
        allowedAccounts
        authorizerArn
        authorizerType
      }
    }
  }
}
Image of Updated Distribution Center Node Settings

At this point, your Lambda function should receive notifications whenever new blocks are created - say when a new item is added, modified, or deleted.

Generate a New Block

Let's go ahead and create a new inventory item. Run the following mutation from the DistributionCenter GraphQL Explorer to add Awesome New Thing to our inventory so that Retailer1 and Retailer2 can start selling it.

mutation newInventoryItem {
  addInventoryItem_async(
    input: {
      itemName: "Awesome New Thing",
      itemNumber: "abc123",
      quantity: 2000,
      tags: [
        "awesome",
        "new",
        "thing"
      ]
    }
  ) {
    error
    result {
      id
      submission_time
      tx_id
    }
  }
}
Image of New Inventory Item

Verify Lambda Was Triggered

Let's go back to our AWS account and open up the CloudWatch Logs log group associated with our Lambda function lambda-block-function-in-your-account. It will have the format /aws/lambda/lambda-block-function-in-your-account.

You should see the log entry with your block ID.

CloudWatch Log Entry When New Item Added

For more information, please refer to Real-time Block Notifications.

Step 8 - Cleanup

It is important that the uni created in this Quick Start is destroyed to prevent any unexpected charges. You can destroy the uni from the Vendia Share Website or with the share CLI command below.

share uni delete --uni test-inventory --force

NOTE: The --uni argument should be adjusted to reflect the name of your Uni as defined by the name property in the registration.json file.

WARNING Deleting a uni is destructive and will remove all of its underlying data.

Summary and Next Steps

This Quick Start demonstrated the ease and speed of which Vendia Share can be leveraged to create serverless resources from a JSON Schema representation of your data model. Without providing anything other than the underlying model, Vendia Share was able to provide a strongly typed interface to your underlying data.

We invite you to explore other Quick Starts. If you would like to hear more about how customers use Vendia Share, reach out today. We would enjoy discussing this exciting platform with you in more detail.

Show table of contents
Edit this page