Users can browse available products on a display or interface, select one, and complete a purchase.
The system supports various payment methods including cash, coins, credit/debit cards, and mobile payments.
The system tracks product stock levels in real time, updates inventory after each transaction, and generates alerts when stock falls below a minimum threshold.
The system issues a refund for the payment amount if a transaction fails or the user cancels it.
Authorized service personnel can access the machine in a maintenance mode for restocking products, performing repairs, updating configuration, and viewing diagnostic information.
Non-Functional Requirements:
Should be reliable (Tracking product inventory and payment made should always be accurate)
Should have high availability (Should have a 99.9% uptime)
Should be secure (User payments should be encrypted in transit to ensure privacy)
Should be scalable (We should be able to increase the number of machines and handle more transactions)
Calculations:
Assume we get around 500 million transactions a day across all vending machines.
Assume each machine can hold about 10 of each product and can hold 30 different products.
500 million transactions a day * 365 days = 182.5 billion
First, the Client will make a request to the Local Cache to store the information in case the service is offline. This will ensure that the user can still use the service but we will only perform the updates to the cloud after the service is back online.
After the change has been made to the local cache, we will direct the request to the Load Balancer to distribute the request to the servers.
When a user makes a payment, we will send the payment to a third party payment processor such as stripe and retrieve a payment token. Then, we will make a request to the buyProduct API in the Vending Machine Service to verify that the payment has been made, update the quantity of the stock in the database, and give the user their product.
If a third party payment processing service is down, we can display a message to the user that we currently only take cash.
The Vending Machine service is a central server that can handle things such as updating stock for a product, getting product information for a specific machine, or getting status and logs for any machine. It will also handle sending messages to the SQS when an issue has been detected or stock for a product has been reduced below a certain threshold and trigger the SMS service and make a call to the maintenance team.
We will detect that an item is low stock if after the user makes a purchase, the item has been reduced to below 10% of its max capacity. This will automatically trigger the SQS message.
Detailed Component Design
Vending Machine Service
getProducts will take in a machineId so that we can list all of the available products and its quantity to the user on the UI.
buyProducts will take in a machineId, a productId, and a paymentType so that we can send this request to the main server, update the stock, process the payment, and give the user their product. If the user chooses card as a paymentType, we will first encrypt the card information on a hardware level, send the request to a third party payment processor, and retrieve the payment token. The payment token will be sent alongside our request to the main server.
If payment verification fails, we can cancel the request and return an error the user on the UI. Since payment comes before making the actual request, we don't need to perform rollback.
If payment is successful but product dispensing has failed, we will automatically trigger a refund and database update. Furthermore, we can also trigger a call to the maintenance team to handle the issue.
buyProduct will also perform an atomic operation on the database to reduce the count of that product by 1. This will ensure that we do not have any race conditions. We will also have the request go through a load balancer first to distribute incoming transactions across our servers.
If the stock of an item drops below 10%, this will trigger an automatic SQS message to trigger the SMS Service. The SMS Service will automatically call the maintenance team to restock the item.
updateStock will take a machineId, a productId, and a productQuantity to update that quantity in the database. It will also take an authorizationToken so that only authorized users can make this request. The authorizationToken can be retrieved at the hardware level (such as scanning a badge).
getStatus and getLogs will take the machineId and an authorizationToken so that we can retrieve the current information about the machine such as dispenser jammed, payment processor tampered with, etc. and getLogs will return the recent logs made to the machine such as recently bought, recently restocked, etc.
On every individual machine, it will automatically detect its own health status at the hardware level. When a dispenser is jammed or payment processor is broken for example, it will automatically detect that and trigger an event in our main Vending Machine Service to trigger an SQS message to call the maintenance team.
If the service is down, fails mid-transaction, or network is limited due to spike in transactions during peak hours, we will track every request through the local cache. The local cache will continue to persist until the service is back online and we can handle all of the offline requests. To ensure that the local cache is never stale, all purchases will go through the local cache.
Tech Choice/Trade Offs
Amazon RDS, SQS
We have decided to go with a relational database instead of a non-relational because we want to ensure data accuracy over speed.
We have decided against using a cache in the cloud because we will not be making that many requests to the same machine often (At most a machine will take about 100-300 requests per day) and we want to ensure data accuracy.