Skip to main content

12. Design Vending Machine System

Step 1: Clarify the requirements

Functional Requirement

  • Display a range of items 展示商品
  • Accepts user payment (cash, credit card, phone payment) 接受用户付款
  • Dispense the item after payment 付款后发放商品
  • Show product prices and information 显示商品价格和信息
  • Inventory management, for managing all the vending machines and their inventory
  • Payment system
  • Notification system, notify the owner company about inventory status

Non-Functional Requirement

  • Network Stability 网络稳定
    • TCP: Reliable, ensures that data sent is received completely and correctly.
    • MQTT: Commonly used in Iot, Remote controlling. It's a light-weight protocol, and it's not reliable in sometimes, eventhought we could choose the QoS (Quality of Service) level.
  • High Availability 高可用性
  • Consistency 一致性

Step 2: Database and Schema

-- machines table
CREATE TABLE machines (
machine_id INT AUTO_INCREMENT PRIMARY KEY,
location VARCHAR(255) NOT NULL,
make VARCHAR(50),
model VARCHAR(50),
status ENUM('ACTIVE', 'INACTIVE', 'MAINTENANCE') NOT NULL,
last_refill_date DATE,
last_service_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- items table
CREATE TABLE items (
item_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
price DECIMAL(5,2) NOT NULL,
description TEXT
);

-- machine_inventory table
CREATE TABLE machine_inventory (
machine_id INT,
item_id INT,
quantity INT NOT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
);

-- transactions table
CREATE TABLE transactions (
transaction_id INT AUTO_INCREMENT PRIMARY KEY,
machine_id INT,
item_id INT,
transaction_amount DECIMAL(5,2) NOT NULL,
transaction_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
status ENUM('PENDING', 'SUCCESS', 'FAILED') NOT NULL,
);

-- users table
CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
role ENUM('ADMIN', 'OPERATOR') NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);


Step 3: API Designs

Machine management

Get a list of all machines

GET /v1/machines
Response:

[
{
"machine_uuid": 1,
"location": "1st Floor, Building A",
"status": "ACTIVE"
},
...
]

Check machine's heartbeat

GET /machines/{machine_id}/status
Response:
{
"status": "ACTIVE"
}

Get all products and their prices on a single machine

GET /v1/machines/{machine_id}/items
Response:

[
{
"item_id": 1,
"item_name": "Coke",
"item_price": 1.5
},
...
]

User purchases items

  • Check inventory 检查库存: Confirm the item is in stock before buying.
  • Give change (In cash) 找零: Return change if the user overpays
  • Transactions 事务: Keep Transactions during purchase to avoid issues.
Endpoint: /v1/machines/{machine_id}/purchase
Method: POST
Request:
{
"item_id": 2,
"quantity": 1,
"payment_amount": 1.5
}
// Success
{
"status": "success",
"change_amount": 0.0,
"message": "Thank you for your purchase."
}
// Failure
{
"status": "failed",
"message": "Insufficient stock or payment amount."
}

Release an item

POST /machines/{machine_id}/release
Request:
{
"item_id": "123",
"transaction_id": "456"
}

Response:
{
"status": "success"
}

Payment system

  • PCI Safety: Keep Payment Card Industry (PCI) standards
  • Transactions and Idempotency 事务与幂等:
    • Make payments transactional to roll back errors.
    • Ensure APIs give same result even if called multiple times
  • HTTPS: Use HTTPS to encrypt data during transfer
  • Tokenization or Hashing: Convert sensitive data to a token or a hashing value, not in plain text

Start a payment transaction

Endpoint: /api/startPayment
Method: POST
Request:
{
"machineId": "MCH12345",
"ItemId": "ITEM98765",
"paymentMethod": "CREDIT_CARD" // CASH", "CREDIT_CARD", "APPLE_PAY"
}

Response:
{
"transactionId": "TXN0011223344",
"amountDue": "5.50"
}

Process a payment

Endpoint: /api/completePayment
Method: POST
Request:
{
"transactionId": "TXN0011223344",
"amountPaid": 6.00,
"paymentDetails": {
"cardNumber": "4111111111111111",
"expiryDate": "12/25",
"cvv": "123"
}
}
Response:
{
"change": 0.50,
"status": "SUCCESS"
}

Step 4: Services

Step 5: Scale Up