Trigger icon
Query icon
If icon
IonToCsv icon
Query icon
Queries icon
SlackIncomingWebhook icon
Log icon

MariaDB Inventory Replenishment & Budget Approval Pipeline with DuckDB SQL

Query MariaDB for low-stock inventory items, analyze reorder cost in DuckDB, and automate budget approvals or Slack alerts with Kestra.

Categories
BusinessData

Automate inventory low-stock monitoring and budget-gated replenishment workflows for MariaDB. This flow polls MariaDB for items below threshold, converts the result set to CSV, calculates total reorder costs and SKU lists using DuckDB in-memory SQL, and evaluates aggregate cost against a configurable budget limit. If within budget, it updates MariaDB item status to REORDER_PENDING and posts a purchase order digest to Slack; otherwise, it alerts the team for manual approval.

What you get

  • Automated polling trigger (io.kestra.plugin.jdbc.mariadb.Trigger) for low-stock inventory events.
  • Zero-footprint in-memory SQL aggregation using DuckDB (io.kestra.plugin.jdbc.duckdb.Query).
  • Budget-gated conditional branching (io.kestra.plugin.core.flow.If).
  • Automated status updates (UPDATE inventory SET reorder_status = 'REORDER_PENDING') upon budget approval.
  • Targeted Slack notifications for both approved purchase orders and budget-exceeded manual approval requests.

Prerequisites

  • A MariaDB database reachable from Kestra.
  • A Slack incoming webhook URL for notifications.
  • Docker networking note: When Kestra runs inside Docker and MariaDB runs on the host machine, use host.docker.internal in MARIADB_URL (e.g., jdbc:mariadb://host.docker.internal:3306/warehouse). On Linux Docker Engine, host.docker.internal may need extra_hosts: "host.docker.internal:host-gateway".
  • Quick Docker MariaDB setup:
    docker run --name mariadb-inventory -e MARIADB_ROOT_PASSWORD=<choose-a-password> -e MARIADB_DATABASE=warehouse -p 3306:3306 -d mariadb:latest
    

Secrets

  • MARIADB_URL: JDBC URL for MariaDB (e.g. jdbc:mariadb://db.example.com:3306/warehouse).
  • MARIADB_USERNAME: Database username.
  • MARIADB_PASSWORD: Database password.
  • SLACK_WEBHOOK_URL: Slack Incoming Webhook URL.

Quick start

  1. Run the seed SQL script in your MariaDB database.
  2. Configure the required secrets in Kestra.
  3. Run the flow manually or enable the MariaDB trigger.

Expected output

  • fetch_low_stock extracts matching items as Ion storage URI {{ outputs.fetch_low_stock.uri }}.
  • check_has_low_stock evaluates {{ outputs.fetch_low_stock.size > 0 }}. If no items match, it logs a notice and skips downstream processing.
  • With the seed data, fetch_low_stock matches 4 low-stock items (SKU-1001, SKU-1002, SKU-1004, SKU-1005) for a total reorder quantity of 117 units and aggregate cost of $1,705.00 (sku_list = SKU-1001,SKU-1002,SKU-1004,SKU-1005).
  • convert_to_csv converts the Ion result to CSV format.
  • analyze_replenishment outputs total_items: 4, total_reorder_qty: 117, total_cost: 1705.00, and sku_list: "SKU-1001,SKU-1002,SKU-1004,SKU-1005".
  • If budget_limit is at default ($2,000.00), total_cost (1705.00) <= 2000.00 is true: update_reorder_status sets reorder_status = 'REORDER_PENDING' for the 4 SKUs and posts a PO digest to Slack.
  • If budget_limit is set to $1,000.00, total_cost (1705.00) <= 1000.00 is false: mark_approval_required sets reorder_status = 'APPROVAL_REQUIRED' in MariaDB and send_manual_approval_slack posts a manual approval alert to Slack stating that no purchase order was created. A manager resolves this by setting item status to 'REORDER_PENDING' to approve reordering or 'OK' to re-evaluate.
  • Trigger note: The trigger SQL uses fixed literal values (quantity_on_hand <= 50 AND reorder_status = 'OK') because trigger queries in Kestra cannot reference flow inputs.

Re-running / Testing Note

To reset the inventory table state back to OK for re-testing or subsequent manual runs:

UPDATE inventory SET reorder_status = 'OK';

Seed SQL

CREATE TABLE IF NOT EXISTS inventory (
    item_id INT AUTO_INCREMENT PRIMARY KEY,
    sku VARCHAR(50) NOT NULL UNIQUE,
    item_name VARCHAR(100) NOT NULL,
    warehouse_location VARCHAR(50) NOT NULL,
    quantity_on_hand INT NOT NULL,
    reorder_threshold INT NOT NULL,
    reorder_quantity INT NOT NULL,
    unit_cost DECIMAL(10,2) NOT NULL,
    reorder_status VARCHAR(50) DEFAULT 'OK',
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

INSERT INTO inventory (sku, item_name, warehouse_location, quantity_on_hand, reorder_threshold, reorder_quantity, unit_cost, reorder_status) VALUES
    ('SKU-1001', 'Wireless Scanner', 'WH-WEST', 12, 50, 10, 45.50, 'OK'),
    ('SKU-1002', 'Label Printer', 'WH-WEST', 8, 30, 5, 120.00, 'OK'),
    ('SKU-1003', 'Packing Tape Reel', 'WH-EAST', 150, 50, 50, 3.25, 'OK'),
    ('SKU-1004', 'Cardboard Box Pack', 'WH-EAST', 25, 50, 100, 1.50, 'OK'),
    ('SKU-1005', 'Pallet Jack', 'WH-SOUTH', 3, 10, 2, 250.00, 'OK');

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.