Track and Trace Quick Start

Note: This quickstart uses a 4-node Uni configuration, which is not viable for Starter tier users given the node limits enforced. See full details on the Pricing page.

The management of risk within a supply chain is crucial to control cost and ensure customer commitments are met. Visibility into supply chain activities and inventory handling is paramount in identifying risks and opportunities. For example, manufacturers may wish to identify patterns in shipping activities that have previously damaged goods. When supply chain logistics extended beyond a single organization to include shippers, retails, and other parties, this visibility can only be enabled through the sharing of data. Vendia Unis provide a platform for sharing data and code with partners in real-time across geographies, cloud-accounts, and technology stacks.

In this Quick start, you will demonstrate how Vendia Unis can easily be implemented to track and trace goods in a supply chain as they move from manufacturer to shipper and ultimately to retailers.

By the end of this Quick start you will have:

  • Created a Universal Application (Uni) with a pre-defined data-model
  • Defined a network of business partners and on-boarded them to the Uni
  • Used the automatically generated HTTPS GraphQL API to interact with the Uni
  • Quickly performed an analysis of supply chain data to answer business questions

Prerequisites

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 Uni.

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 @vendia/share-cli -g

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

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

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 four collections of data:

TypeDescription
InventoryInventory records provide information about products including their Name, SKU, Location, and Quantity on Hand.
ShipmentShipment records reflect the movement of products to and from locations in the supply chain.
OrderOrder records reflect a purchase of inventory from the manufacturer that will require a shipment for delivery to a retailer.
WarehouseWarehouse records detail the locations along the supply chain where partners may store goods throughout the manufacturing, shipping, and receiving activities.

Save the Quick Start Files Below

The registration.json, schema.json, and initial-state.json will be referenced by the CLI later. Please save these files locally by expanding each node and copying the contents.

Registration file - save as registration.json

The registration.json file defines the Uni name, location of the schema, and the node configuration representing partners in the supply chain network. In this example, you will define a manufacturer, a shipper, and two retailers.

NOTES

  • You will need to provide your Vendia Share userId when defining your nodes. For the quick start, please use your same userId across all nodes.
  • 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.
  • Starter tier users must (and Pro tier users may prefer to) continue with this example using only 2 of the nodes defined in the registration.json file below. See full details on the Pricing page.

{
  "name": "test-track-and-trace",
  "schema": "schema.json",
  "initState": "initial-state.json",
  "nodes": [{
      "name": "manufacturer",
      "userId": "me@domain.com",
      "region": "us-east-2",
      "settings": {
        "apiSettings": {
          "auth": {
            "authorizerType": "API_KEY"
          }
        }
      }
    },
    {
      "name": "shipper",
      "userId": "me@domain.com",
      "region": "us-east-2",
      "settings": {
        "apiSettings": {
          "auth": {
            "authorizerType": "API_KEY"
          }
        }
      }
    },
    {
      "name": "retailer01",
      "userId": "me@domain.com",
      "region": "us-west-2",
      "settings": {
        "apiSettings": {
          "auth": {
            "authorizerType": "API_KEY"
          }
        }
      }
    },
    {
      "name": "retailer02",
      "userId": "me@domain.com",
      "region": "us-west-2",
      "settings": {
        "apiSettings": {
          "auth": {
            "authorizerType": "API_KEY"
          }
        }
      }
    }
  ]
}
Schema file - save as schema.json

The schema.json file defines the data model for the Uni and is used to automatically generate the API that will be used later to interact with the system. This file defines the record types previously mentioned. Save it as schema.json on your local workstation in the same directory as the registration.json file you saved prior.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "http://vendia.net/schemas/demos/track-and-trace.json",
  "title": "Track and Trace",
  "description": "Track and trace shipments among a manufacturer, shipper, and retailer",
  "type": "object",
  "properties": {
    "Inventory": {
      "description": "Inventory information",
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "description": "Product name",
            "type": "string"
          },
          "sku": {
            "description": "Product SKU",
            "type": "string"
          },
          "warehouse": {
            "description": "Manufacturer warehouse code",
            "type": "string"
          },
          "availableInventory": {
            "description": "Available inventory",
            "type": "integer"
          }
        }
      }
    },
    "Shipment": {
      "description": "Shipment information",
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "originWarehouse": {
            "description": "Shipment origin",
            "type": "string"
          },
          "destinationWarehouse": {
            "description": "Shipment destination",
            "type": "string"
          },
          "orderId": {
            "description": "Order ID",
            "type": "string"
          },
          "created": {
            "description": "When the order was placed",
            "type": "string",
            "format": "date-time"
          },
          "lastUpdated": {
            "description": "When the order was last updated",
            "type": "string",
            "format": "date-time"
          },
          "location": {
            "description": "Current Lat/long of the shipment",
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "uniqueItems": true
          },
          "delivered": {
            "description": "Delivery status",
            "type": "boolean"
          }
        }
      }
    },
    "Order": {
      "description": "Order information",
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "orderId": {
            "description": "Order ID",
            "type": "string"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "sku": {
                  "description": "Product SKU in order",
                  "type": "string"
                },
                "quantity": {
                  "description": "Quantity of product in order",
                  "type": "integer"
                }
              }
            }
          },
          "manufacturerWarehouseCode": {
            "description": "Manufacturer warehouse that holds the inventory",
            "type": "string"
          },
          "manufacturerWarehouseLocation": {
            "description": "Lat/long of manufacturer warehouse",
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "uniqueItems": true
          },
          "retailerWarehouseCode": {
            "description": "Retailer warehouse that placed the order",
            "type": "string"
          },
          "retailerWarehouseLocation": {
            "description": "Lat/long of retailer warehouse",
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "uniqueItems": true
          },
          "delivered": {
            "description": "Order status",
            "type": "boolean"
          },
          "created": {
            "description": "When order was placed",
            "type": "string",
            "format": "date-time"
          },
          "updated": {
            "description": "When order was last updated",
            "type": "string",
            "format": "date-time"
          }
        }
      }
    },
    "Warehouse": {
      "description": "Warehouse information",
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "companyName": {
            "description": "Company name",
            "type": "string"
          },
          "code": {
            "description": "Warehouse code",
            "type": "string"
          },
          "street1": {
            "description": "Warehouse Street Address",
            "type": "string"
          },
          "street2": {
            "description": "Warehouse Warehouse Street Address Continued",
            "type": "string"
          },
          "city": {
            "description": "Warehouse City",
            "type": "string"
          },
          "state": {
            "description": "Warehouse State",
            "type": "string"
          },
          "postalCode": {
            "description": "Warehouse Postal Code",
            "type": "string"
          },
          "country": {
            "description": "Warehouse Country Code",
            "type": "string"
          },
          "phone": {
            "description": "Warehouse Phone Number",
            "type": "string"
          },
          "fax": {
            "description": "Warehouse Fax Number",
            "type": "string"
          },
          "created": {
            "description": "When the Warehouse record was created",
            "type": "string",
            "format": "date-time"
          },
          "updated": {
            "description": "When Warehouse record was last updated",
            "type": "string",
            "format": "date-time"
          }
        }
      }
    }
  }
}
Initial State file - save as initial-state.json

The initial-state.json file allows for the population of pre-existing data when creating a Uni. In this example, the initial-state.json file is pre-populated with Inventory, Warehouse, Order, and Shipment data.

Save this file as initial-state.json in the same directory as the prior files.

{
  "Inventory": [{
      "name": "Widget 123 - 1 count",
      "sku": "WMl237ABC",
      "warehouse": "manufacturer",
      "availableInventory": 100
    },
    {
      "name": "Widget 123 - 5 count",
      "sku": "WMl237DEF",
      "warehouse": "manufacturer",
      "availableInventory": 12
    },
    {
      "name": "Widget 123 - 10 count",
      "sku": "WMl237GHI",
      "warehouse": "manufacturer",
      "availableInventory": 83
    },
    {
      "name": "Widget 123 - 50 count",
      "sku": "WMl237JKL",
      "warehouse": "manufacturer",
      "availableInventory": 20
    },
    {
      "name": "Widget 456 - 1 count",
      "sku": "WMl237MNP",
      "warehouse": "manufacturer",
      "availableInventory": 10
    },
    {
      "name": "Widget 456 - 5 count",
      "sku": "WMl237QRS",
      "warehouse": "manufacturer",
      "availableInventory": 350
    },
    {
      "name": "Widget 456 - 10 count",
      "sku": "WMl237TUV",
      "warehouse": "manufacturer",
      "availableInventory": 1250
    },
    {
      "name": "Widget 456 - 50 count",
      "sku": "WMl237WXY",
      "warehouse": "manufacturer",
      "availableInventory": 49
    }
  ],
  "Warehouse": [{
      "companyName": "Manufacturing Company",
      "code": "manufacturer",
      "street1": "3543 Queens Lane",
      "city": "Keysville",
      "state": "VA",
      "postalCode": "23947",
      "country": "US",
      "phone": "4345553444",
      "fax": "4345553445",
      "created": "2020-12-01T14:10:02Z",
      "updated": "2020-12-01T14:10:02Z"
    },
    {
      "companyName": "Retailer Inc",
      "code": "retailer01",
      "street1": "558 Wilkinson Ct",
      "street2": "ste 1402",
      "city": "Maple Valley",
      "state": "WA",
      "postalCode": "98038",
      "country": "US",
      "phone": "4255551314",
      "fax": "3605553213",
      "created": "2020-12-01T14:10:02Z",
      "updated": "2020-12-01T14:10:02Z"
    },
    {
      "companyName": "Outlet Shops LLC",
      "code": "retailer02",
      "street1": "3449 Wolf Pen Rd",
      "city": "San Francisco",
      "state": "CA",
      "postalCode": "94107",
      "country": "US",
      "phone": "6505559544",
      "fax": "4155556254",
      "created": "2020-12-01T14:10:02Z",
      "updated": "2020-12-01T14:10:02Z"
    }
  ],
  "Order": [{
      "orderId": "manufacturer-01",
      "items": [{
        "sku": "WMl237TUV",
        "quantity": 10
      }],
      "manufacturerWarehouseCode": "manufacturer",
      "manufacturerWarehouseLocation": [37.04827632907081, -78.48873356671945],
      "retailerWarehouseCode": "retailer01",
      "retailerWarehouseLocation": [47.37441523471446, -122.03460569672072],
      "delivered": true,
      "created": "2020-12-02T14:10:02Z",
      "updated": "2020-12-02T14:10:02Z"
    },
    {
      "orderId": "manufacturer-02",
      "items": [{
        "sku": "WMl237JKL",
        "quantity": 6
      }],
      "manufacturerWarehouseCode": "manufacturer",
      "manufacturerWarehouseLocation": [37.04827632907081, -78.48873356671945],
      "retailerWarehouseCode": "retailer02",
      "retailerWarehouseLocation": [37.72443674615711, -122.49047216194155],
      "delivered": false,
      "created": "2020-12-02T14:10:02Z",
      "updated": "2020-12-02T14:10:02Z"
    },
    {
      "orderId": "manufacturer-03",
      "items": [{
          "sku": "WMl237DEF",
          "quantity": 2
        },
        {
          "sku": "WMl237MNP",
          "quantity": 4
        }
      ],
      "manufacturerWarehouseCode": "manufacturer",
      "manufacturerWarehouseLocation": [37.04827632907081, -78.48873356671945],
      "retailerWarehouseCode": "retailer02",
      "retailerWarehouseLocation": [37.72443674615711, -122.49047216194155],
      "delivered": false,
      "created": "2020-12-02T14:10:02Z",
      "updated": "2020-12-02T14:10:02Z"
    }
  ],
  "Shipment": [{
      "originWarehouse": "manufacturer",
      "destinationWarehouse": "retailer01",
      "orderId": "manufacturer-01",
      "created": "2020-12-02T14:10:02Z",
      "lastUpdated": "2020-12-02T14:10:02Z",
      "location": [47.37441523471446, -122.03460569672072],
      "delivered": false
    },
    {
      "originWarehouse": "manufacturer",
      "destinationWarehouse": "retailer02",
      "orderId": "manufacturer-02",
      "created": "2020-12-02T14:10:02Z",
      "lastUpdated": "2020-12-02T14:10:02Z",
      "location": [40.20448090000001, -74.5759279],
      "delivered": false
    },
    {
      "originWarehouse": "manufacturer",
      "destinationWarehouse": "retailer01",
      "orderId": "manufacturer-03",
      "created": "2020-12-02T14:10:02Z",
      "lastUpdated": "2020-12-02T14:10:02Z",
      "location": [40.19557037731903, -74.56602928070187],
      "delivered": false
    }
  ]
}

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

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-track-and-trace

Please refer to the Vendia Share CLI documentation for more detailed information.

Step 3 - Preparing to Interact with Uni Data

The easiest way to work with Uni data is via the Graphql API. You can access the GraphQL API with a web browser by visiting the GraphQL Explorer for your Uni.

Open the details page for your Uni and click on the GraphQL explorer button for any node.

Remember, Uni data is available in real-time from any node, so you can explore the data from any node created in this quick start.

GraphQL Explorer Button

Run your first Query

The GraphQL Explorer window will be pre-populated with an example query. Delete this query and replace it with the sample below to list the pre-loaded inventory information. Run the query by pressing the play button and review the list of products.

query listInventory {
  list_InventoryItems {
    _InventoryItems {
      _id
      name
      sku
      availableInventory
      warehouse
    }
  }
}

Step 4 - Track Products in the Supply Chain Network

Now that the Uni is operational and data has been loaded, the GraphQL Explorer can be used to further inspect the state of orders and shipments.

Where is My Delivery?

Imagine that Retailer Inc., represented by the code retailer01 in our network, has called regarding a delivery. The retailer provides the order id manufacturer-01.

Using the following query in the GraphQL Explorer, determine the Delivery status and Location of the related shipment.

query manufacturing0102Shipment {
  list_ShipmentItems(
    filter: {
      orderId: {eq: "manufacturer-01"}
    }
  ) {
    _ShipmentItems {
      _id
      orderId
      delivered
      originWarehouse
      destinationWarehouse
      location
      created
      lastUpdated
    }
  }
}

Example Output

{
  "data": {
    "list_ShipmentItems": {
      "_ShipmentItems": [
        {
          "_id": "017d1206-7881-4279-995a-e4176d8f223a",
          "orderId": "manufacturer-01",
          "delivered": false,
          "originWarehouse": "manufacturer",
          "destinationWarehouse": "retailer01",
          "location": [
            47.3744,
            -122.035
          ],
          "created": "2020-12-02T14:10:02Z",
          "lastUpdated": "2020-12-02T14:10:02Z"
        }
      ]
    }
  }
}

A quick review of the results show the order was not delivered and was last reported at the location 47.3744, -122.035.

Note the _id of the shipment record returned. That will be useful in the next step.

A quick review of the location on a map suggests this package may be irretrievably lost.

Map Image

While the storage and retrieval of order data is useful, it may become necessary to review the history of the shipment data for deeper insights. For the purposes of this example, assume the package was retrieved from Lake Wilderness successfully and re-routed to its intended destination.

Progress the shipment by updating the shipment with new location data. Copy and paste the following mutation to update the shipment.

Important
As the id of each record in the initial-state is generated by the Uni when we create it, you must update the id value on line one to match the _id of the shipment record you noted in the previous step. This value is specific to your Uni.

Note: While you can apply mutations from any node in the Uni in this quick start, each mutation will be written with metadata regarding its source. For demonstration purposes, imagine that you are acting on behalf of the Shipper and run the mutations from the Shipper node.

mutation UpdateShipment($shipmentId: ID!="YOUR ID HERE") {

    update_Shipment(id: $shipmentId, input: {
            created: "2020-12-02T14:10:02Z",
            delivered: false,
            destinationWarehouse: "retailer01",
            lastUpdated: "2020-12-02T15:10:02Z",
            location: [
                47.61520116708219,
                -122.35427961729266
            ],
            orderId: "manufacturer-01",
            originWarehouse: "manufacturer"
        },     
        syncMode: ASYNC) {
        transaction {
            transactionId
        }
    }
}

Example Output

{
  "data": {
    "update_Shipment": {
      "transaction": {
        "transactionId": "017d7e4b-04e2-e742-5c1b-badeb90b6617"
      }
    }
  }
}

Once the mutation is executed, a transactionId value will be returned, which can be used to track the transaction through its full lifecycle.

Query the shipment again to verify its intended location was updated.

query manufacturing0102Shipment {
    list_ShipmentItems(
        filter: {
            orderId: {eq: "manufacturer-01"}
        }
    ) {
        _ShipmentItems {
            _id
            orderId
            delivered
            originWarehouse
            destinationWarehouse
            location
            created
            lastUpdated
        }
    }
}

Hooray! The shipment was successfully delivered. Apply another mutation with new delivered status and lastUpdated data.

mutation UpdateShipment($shipmentId: ID!="017d7e12-5c29-165b-6051-f56a03bcb45e") {
    update_Shipment (id: $shipmentId, input: {
        delivered: true,
        lastUpdated: "2020-12-02T16:10:02Z"
    }, syncMode: ASYNC) {
        transaction {
            _id
        }
    }
}

List the shipment one final time.

query manufacturing0102Shipment {
    list_ShipmentItems(
        filter: {
            orderId: {eq: "manufacturer-01"}
        }
    ) {
        _ShipmentItems {
            _id
            orderId
            delivered
            originWarehouse
            destinationWarehouse
            location
            created
            lastUpdated
        }
    }
}

The result shows the shipment made it to its final destination.

{
  "data": {
    "list_ShipmentItems": {
      "_ShipmentItems": [
        {
          "_id": "017d7e12-5c29-165b-6051-f56a03bcb45e",
          "orderId": "manufacturer-01",
          "delivered": true,
          "originWarehouse": "manufacturer",
          "destinationWarehouse": "retailer01",
          "location": [
            47.6152,
            -122.354
          ],
          "created": "2020-12-02T14:10:02Z",
          "lastUpdated": "2020-12-02T16:10:02Z"
        }
      ]
    }
  }
}

Because they are backed by an immutable distributed ledger, Vendia Unis contain the history of records as they are updated. You can query the ledger history with GraphQL to review past mutations.

query ledger {
  listVendia_BlockItems {
    Vendia_BlockItems {
      _id
      commitTime
      transactions {
        mutations
        _owner
      }
    }
  }
}
Transaction ledger
{
  "data": {
    "listVendia_BlockItems": {
      "Vendia_BlockItems": [
        {
          "_id": "000000000000001",
          "commitTime": "2021-12-03T02:21:44.823553+00:00",
          "transactions": [
            {
              "mutations": [
                "addSelf_Inventory(id:\"017d7e12-4be5-3a78-d0bf-a4a31962d4d2\", input: {name: \"Widget 123 - 10 count\", sku: \"WMl237GHI\", warehouse: \"manufacturer\", availableInventory: 83}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Shipment(id:\"017d7e12-5c29-165b-6051-f56a03bcb45e\", input: {originWarehouse: \"manufacturer\", destinationWarehouse: \"retailer01\", orderId: \"manufacturer-01\", created: \"2020-12-02T14:10:02Z\", lastUpdated: \"2020-12-02T14:10:02Z\", location: [47.3744, -122.035], delivered: true}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Order(id:\"017d7e12-5964-fd6e-5fc6-de578a144367\", input: {orderId: \"manufacturer-02\", items: [{sku: \"WMl237JKL\", quantity: 6}], manufacturerWarehouseCode: \"manufacturer\", manufacturerWarehouseLocation: [37.0483, -78.4887], retailerWarehouseCode: \"retailer02\", retailerWarehouseLocation: [37.7244, -122.49], delivered: false, created: \"2020-12-02T14:10:02Z\", updated: \"2020-12-02T14:10:02Z\"}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Inventory(id:\"017d7e12-5000-b93f-6ec4-ddba5ee13109\", input: {name: \"Widget 456 - 5 count\", sku: \"WMl237QRS\", warehouse: \"manufacturer\", availableInventory: 350}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Shipment(id:\"017d7e12-5d68-52d9-60d1-f31a15762edb\", input: {originWarehouse: \"manufacturer\", destinationWarehouse: \"retailer02\", orderId: \"manufacturer-02\", created: \"2020-12-02T14:10:02Z\", lastUpdated: \"2020-12-02T14:10:02Z\", location: [40.2045, -74.5759], delivered: false}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Order(id:\"017d7e12-5aea-0375-f236-94025c3f1474\", input: {orderId: \"manufacturer-03\", items: [{sku: \"WMl237DEF\", quantity: 2}, {sku: \"WMl237MNP\", quantity: 4}], manufacturerWarehouseCode: \"manufacturer\", manufacturerWarehouseLocation: [37.0483, -78.4887], retailerWarehouseCode: \"retailer02\", retailerWarehouseLocation: [37.7244, -122.49], delivered: false, created: \"2020-12-02T14:10:02Z\", updated: \"2020-12-02T14:10:02Z\"}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Inventory(id:\"017d7e12-4e63-e57e-5ae8-32eea308d82e\", input: {name: \"Widget 456 - 1 count\", sku: \"WMl237MNP\", warehouse: \"manufacturer\", availableInventory: 10}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Order(id:\"017d7e12-5811-fc6d-c931-aad502d6f168\", input: {orderId: \"manufacturer-01\", items: [{sku: \"WMl237TUV\", quantity: 10}], manufacturerWarehouseCode: \"manufacturer\", manufacturerWarehouseLocation: [37.0483, -78.4887], retailerWarehouseCode: \"retailer01\", retailerWarehouseLocation: [47.3744, -122.035], delivered: true, created: \"2020-12-02T14:10:02Z\", updated: \"2020-12-02T14:10:02Z\"}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Warehouse(id:\"017d7e12-5696-1029-2170-433edcc9a488\", input: {companyName: \"Outlet Shops LLC\", code: \"retailer02\", street1: \"3449 Wolf Pen Rd\", city: \"San Francisco\", state: \"CA\", postalCode: \"94107\", country: \"US\", phone: \"6505559544\", fax: \"4155556254\", created: \"2020-12-01T14:10:02Z\", updated: \"2020-12-01T14:10:02Z\"}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Inventory(id:\"017d7e12-4a64-56c4-ff78-94ada52294d7\", input: {name: \"Widget 123 - 5 count\", sku: \"WMl237DEF\", warehouse: \"manufacturer\", availableInventory: 12}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Inventory(id:\"017d7e12-513f-0fcc-7539-e9e948c233a5\", input: {name: \"Widget 456 - 10 count\", sku: \"WMl237TUV\", warehouse: \"manufacturer\", availableInventory: 1250}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Shipment(id:\"017d7e12-5efd-8ca7-46af-6cee30f92989\", input: {originWarehouse: \"manufacturer\", destinationWarehouse: \"retailer01\", orderId: \"manufacturer-03\", created: \"2020-12-02T14:10:02Z\", lastUpdated: \"2020-12-02T14:10:02Z\", location: [40.1956, -74.566], delivered: false}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Inventory(id:\"017d7e12-4d25-2fd8-a835-4e50668c9bcb\", input: {name: \"Widget 123 - 50 count\", sku: \"WMl237JKL\", warehouse: \"manufacturer\", availableInventory: 20}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Warehouse(id:\"017d7e12-5551-7f88-7fe7-95f8fa9805a5\", input: {companyName: \"Retailer Inc\", code: \"retailer01\", street1: \"558 Wilkinson Ct\", street2: \"ste 1402\", city: \"Maple Valley\", state: \"WA\", postalCode: \"98038\", country: \"US\", phone: \"4255551314\", fax: \"3605553213\", created: \"2020-12-01T14:10:02Z\", updated: \"2020-12-01T14:10:02Z\"}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Inventory(id:\"017d7e12-4926-5618-f881-77b5d2e63dbc\", input: {name: \"Widget 123 - 1 count\", sku: \"WMl237ABC\", warehouse: \"manufacturer\", availableInventory: 100}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Inventory(id:\"017d7e12-527b-4787-3f91-f4e21faa42be\", input: {name: \"Widget 456 - 50 count\", sku: \"WMl237WXY\", warehouse: \"manufacturer\", availableInventory: 49}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addVendia_DeploymentInfo(id:\"2021-12-03T02:21:44.823553+00:00\", input: {deploymentTime: \"2021-12-03T02:21:44.823553+00:00\" , consensusDefinitionHash: \"9e0c4a782ed0e5ddefb0a32d4734d690008e7b809847dcc0794499affc7eb505\" , versionTag: \"prod-release.2021-12-02.de91c6d\" } ) {error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "addSelf_Warehouse(id:\"017d7e12-540f-f94b-a54b-99dd262331d0\", input: {companyName: \"Manufacturing Company\", code: \"manufacturer\", street1: \"3543 Queens Lane\", city: \"Keysville\", state: \"VA\", postalCode: \"23947\", country: \"US\", phone: \"4345553444\", fax: \"4345553445\", created: \"2020-12-01T14:10:02Z\", updated: \"2020-12-01T14:10:02Z\"}){error}"
              ],
              "_owner": "manufacturer"
            },
            {
              "mutations": [
                "putVendia_UniInfo(input: {name: \"test-track-n-trace.unis.vendia.net\", sku: \"SHARE\", schema: \"{\\\"$schema\\\":\\\"http://json-schema.org/draft-07/schema#\\\",\\\"$id\\\":\\\"http://vendia.net/schemas/demos/track-and-trace.json\\\",\\\"title\\\":\\\"Track and Trace\\\",\\\"description\\\":\\\"Track and trace shipments among a manufacturer, shipper, and retailer\\\",\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"Inventory\\\":{\\\"description\\\":\\\"Inventory information\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"name\\\":{\\\"description\\\":\\\"Product name\\\",\\\"type\\\":\\\"string\\\"},\\\"sku\\\":{\\\"description\\\":\\\"Product SKU\\\",\\\"type\\\":\\\"string\\\"},\\\"warehouse\\\":{\\\"description\\\":\\\"Manufacturer warehouse code\\\",\\\"type\\\":\\\"string\\\"},\\\"availableInventory\\\":{\\\"description\\\":\\\"Available inventory\\\",\\\"type\\\":\\\"integer\\\"}}}},\\\"Shipment\\\":{\\\"description\\\":\\\"Shipment information\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"originWarehouse\\\":{\\\"description\\\":\\\"Shipment origin\\\",\\\"type\\\":\\\"string\\\"},\\\"destinationWarehouse\\\":{\\\"description\\\":\\\"Shipment destination\\\",\\\"type\\\":\\\"string\\\"},\\\"orderId\\\":{\\\"description\\\":\\\"Order ID\\\",\\\"type\\\":\\\"string\\\"},\\\"created\\\":{\\\"description\\\":\\\"When the order was placed\\\",\\\"type\\\":\\\"string\\\",\\\"format\\\":\\\"date-time\\\"},\\\"lastUpdated\\\":{\\\"description\\\":\\\"When the order was last updated\\\",\\\"type\\\":\\\"string\\\",\\\"format\\\":\\\"date-time\\\"},\\\"location\\\":{\\\"description\\\":\\\"Current Lat/long of the shipment\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"number\\\"},\\\"minItems\\\":2,\\\"uniqueItems\\\":true},\\\"delivered\\\":{\\\"description\\\":\\\"Delivery status\\\",\\\"type\\\":\\\"boolean\\\"}}}},\\\"Order\\\":{\\\"description\\\":\\\"Order information\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"orderId\\\":{\\\"description\\\":\\\"Order ID\\\",\\\"type\\\":\\\"string\\\"},\\\"items\\\":{\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"sku\\\":{\\\"description\\\":\\\"Product SKU in order\\\",\\\"type\\\":\\\"string\\\"},\\\"quantity\\\":{\\\"description\\\":\\\"Quantity of product in order\\\",\\\"type\\\":\\\"integer\\\"}}}},\\\"manufacturerWarehouseCode\\\":{\\\"description\\\":\\\"Manufacturer warehouse that holds the inventory\\\",\\\"type\\\":\\\"string\\\"},\\\"manufacturerWarehouseLocation\\\":{\\\"description\\\":\\\"Lat/long of manufacturer warehouse\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"number\\\"},\\\"minItems\\\":2,\\\"uniqueItems\\\":true},\\\"retailerWarehouseCode\\\":{\\\"description\\\":\\\"Retailer warehouse that placed the order\\\",\\\"type\\\":\\\"string\\\"},\\\"retailerWarehouseLocation\\\":{\\\"description\\\":\\\"Lat/long of retailer warehouse\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"number\\\"},\\\"minItems\\\":2,\\\"uniqueItems\\\":true},\\\"delivered\\\":{\\\"description\\\":\\\"Order status\\\",\\\"type\\\":\\\"boolean\\\"},\\\"created\\\":{\\\"description\\\":\\\"When order was placed\\\",\\\"type\\\":\\\"string\\\",\\\"format\\\":\\\"date-time\\\"},\\\"updated\\\":{\\\"description\\\":\\\"When order was last updated\\\",\\\"type\\\":\\\"string\\\",\\\"format\\\":\\\"date-time\\\"}}}},\\\"Warehouse\\\":{\\\"description\\\":\\\"Warehouse information\\\",\\\"type\\\":\\\"array\\\",\\\"items\\\":{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"companyName\\\":{\\\"description\\\":\\\"Company name\\\",\\\"type\\\":\\\"string\\\"},\\\"code\\\":{\\\"description\\\":\\\"Warehouse code\\\",\\\"type\\\":\\\"string\\\"},\\\"street1\\\":{\\\"description\\\":\\\"Warehouse Street Address\\\",\\\"type\\\":\\\"string\\\"},\\\"street2\\\":{\\\"description\\\":\\\"Warehouse Warehouse Street Address Continued\\\",\\\"type\\\":\\\"string\\\"},\\\"city\\\":{\\\"description\\\":\\\"Warehouse City\\\",\\\"type\\\":\\\"string\\\"},\\\"state\\\":{\\\"description\\\":\\\"Warehouse State\\\",\\\"type\\\":\\\"string\\\"},\\\"postalCode\\\":{\\\"description\\\":\\\"Warehouse Postal Code\\\",\\\"type\\\":\\\"string\\\"},\\\"country\\\":{\\\"description\\\":\\\"Warehouse Country Code\\\",\\\"type\\\":\\\"string\\\"},\\\"phone\\\":{\\\"description\\\":\\\"Warehouse Phone Number\\\",\\\"type\\\":\\\"string\\\"},\\\"fax\\\":{\\\"description\\\":\\\"Warehouse Fax Number\\\",\\\"type\\\":\\\"string\\\"},\\\"created\\\":{\\\"description\\\":\\\"When the Warehouse record was created\\\",\\\"type\\\":\\\"string\\\",\\\"format\\\":\\\"date-time\\\"},\\\"updated\\\":{\\\"description\\\":\\\"When Warehouse record was last updated\\\",\\\"type\\\":\\\"string\\\",\\\"format\\\":\\\"date-time\\\"}}}}}}\", schemaNamespace: \"Self\", status: \"RUNNING\", createdTime: \"2021-12-03T02:14:26.936578+00:00\", updatedTime: \"2021-12-03T02:21:44.823553+00:00\", nodes: [{name: \"manufacturer\", userId: \"512f2d97-979d-4cb5-9b52-04b5f1f7aa3d\", userEmail: \"james+demo@vendia.net\", status: \"RUNNING\", region: \"us-east-2\", tier: {share: FREE}, vendiaAccount: {csp: \"AWS\", accountId: \"255562891666\", org: \"332134949057\"}}, {name: \"shipper\", userId: \"512f2d97-979d-4cb5-9b52-04b5f1f7aa3d\", userEmail: \"james+demo@vendia.net\", status: \"RUNNING\", region: \"us-east-2\", tier: {share: FREE}, vendiaAccount: {csp: \"AWS\", accountId: \"380683105211\", org: \"332134949057\"}}]}) {error}"
              ],
              "_owner": "manufacturer"
            }
          ]
        },
        {
          "_id": "000000000000002",
          "commitTime": "2021-12-03T03:16:32.536005+00:00",
          "transactions": [
            {
              "mutations": [
                "updateSelf_Shipment(id:\"017d7e12-5c29-165b-6051-f56a03bcb45e\",input: {created: \"2020-12-02T14:10:02Z\", delivered: false, destinationWarehouse: \"retailer01\", lastUpdated: \"2020-12-02T15:10:02Z\", location: [47.6152, -122.354], orderId: \"manufacturer-01\", originWarehouse: \"manufacturer\"}){error}"
              ],
              "_owner": "manufacturer"
            }
          ]
        },
        {
          "_id": "000000000000003",
          "commitTime": "2021-12-03T03:23:12.940545+00:00",
          "transactions": [
            {
              "mutations": [
                "updateSelf_Shipment(id:\"017d7e12-5c29-165b-6051-f56a03bcb45e\",input: {delivered: true, lastUpdated: \"2020-12-02T16:10:02Z\"}){error}"
              ],
              "_owner": "manufacturer"
            }
          ]
        }
      ]
    }
  }
}

Note that each block in the ledger is recorded with the Mutation data and metadata regarding the node that submitted the mutation. This can be very useful when researching the lineage of specific data such as when working to identify when and where the Shipment record was updated.

Step 5 - Trace issues with package handling

Sharing scalar data such tracking updates for shipments is easy with Vendia Share but it is only part of the data-sharing story. Another feature that logistics customers value is the ability to share files with nodes inside a Uni.

Imagine that the shipment with which you have been working finally makes it to its intended destination. Upon inspection however, the retailer reports the package has been damaged. Using Vendia Share, we can begin to add physical evidence to the activities in the supply chain to identify where such damage occurs.

Vendia's Glenn Dierkes details a solution for gathering such evidence in a recent Blog Article. This solution takes advantage of Vendia Share's file-sharing feature to allow partners to upload photos of products as they traverse the supply-chain. These photos can then later be correlated to reports of damage to identify loss patterns.

Adding photos to the supply chain

Using the GraphQL Explorer, provide a photo of the damaged item.

mutation addShipmentPhoto {
  addVendia_File(
    input: {
      sourceBucket: "source-s3-bucket",
      sourceKey: "box-image.jpg",
      sourceRegion: "us-east-1",
      destinationKey: "shipment-017d1206-7881-4279-995a-e4176d8f223a-delivery.jpg"
    },
    syncMode: ASYNC
  ) {
    transaction {
      _id
      transactionId
    }
  }
}

NOTE: The sourceBucket and sourceKey should be updated to reflect your data.

This mutation has posted an update to the shipment record and added a file to the Uni at shipment-017d1206-7881-4279-995a-e4176d8f223a-delivery.jpg. This file can be shared with other nodes and presented directly via cloud-based storage services. As the nodes in this Uni are deployed to AWS, the file is accessible via Amazon S3.

Run the following query in GraphQL Explorer to retrieve a temporary URL for the added file.

query listFiles {
  listVendia_FileItems {
    Vendia_FileItems {
      _id
      temporaryUrl
      destinationKey
    }
  }
}

The returned TemporaryUrl can be opened from a web browser to inspect the photo. In this example, it appears the box was left unattended and thus was damaged.

Step 6 - Clean up

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 Share Website or with the CLI command below.

share uni delete --uni test-track-and-trace

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.

Summary and Next Steps

This Quick start demonstrated the ease and speed of which Vendia Share can be leveraged to support supply chain logistics. With zero-code, data was quickly accessible between multiple parties and updates could be recorded and validated in real-time across parties.Vendia Share integrations and smart-contracts could be leveraged to further automate data collection and review. For example, email notifications for deliveries could be modeled against Shipment data and links to view progress on a map could be dynamically generated. If you would like to hear more about how logistics and inventory management customers use Vendia Share, reach out today. We would enjoy discussing this exciting platform with you in more detail.