Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

2 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

markdown

๐Ÿ—ƒ๏ธ InvenSQL

Inventory & Supply Chain Dashboard

Built for the person operating the database, not the person who wrote it.

Python Streamlit MySQL Status


A dashboard where the database, not the app, does the heavy lifting โ€” and the person clicking buttons never has to know that.

Someone running a warehouse doesn't think in INSERT statements. They think "we got a shipment in" or "we're low on this, order more." This project exists to let that person do exactly that โ€” through forms and buttons โ€” while everything underneath is handled with the same rigor a DBA would insist on: stored procedures, transactions, and views doing real multi-table work, invisibly.


๐Ÿ“– Table of Contents


๐Ÿค” Why I Built This

In most small operations, whoever needs to log a new product or receive a shipment has two bad options: ping a developer every single time, or get handed MySQL Workbench and told to "be careful." Neither scales, and the second one is genuinely dangerous โ€” because almost nothing in this schema is a one-table operation.

Adding a product isn't just a product row. It's a product row and an opening shipment record and a stock entry, created together. Receiving a reorder touches the reorder itself, the product's stock count, and a new stock-entry log โ€” four writes across the system for one real-world event. If a person does that by hand across separate statements and one fails, or they run them in the wrong order, or they just fat-finger a value โ€” the database ends up lying. A product that exists but has zero stock. A shipment with no product behind it. A reorder marked received that never actually updated stock.

I didn't want that failure mode to be possible, regardless of who's clicking the button or how much SQL they know. So the actual work of this project isn't the UI โ€” it's pushing every multi-table write down into a MySQL stored procedure wrapped in a transaction, so the database itself enforces "all of this changes together, or none of it does." Streamlit's only job is collecting clean input and calling the procedure. It holds no business logic of its own โ€” if you deleted main.py and called the procedures from a terminal, you'd get identical guarantees.

๐Ÿง‘โ€๐Ÿ’ผ Who It's For

  • A warehouse or inventory manager who needs to log stock without ever opening a query editor
  • A small business owner running their own inventory without a dedicated data or IT team
  • Anyone who needs to perform what a DBA would recognize as a real, multi-table database transaction โ€” without knowing what that phrase means, and without being able to break it even if they tried

Project Preview

Dashboard Overview


โœจ Features

  • ๐Ÿ“Š Live dashboard metrics โ€” supplier count, product count, category count, 3-month sales value, 3-month restock value, and items below reorder level with no pending reorder. These come straight from SQL aggregates rather than being pulled into pandas and summed in Python, so the numbers are always a live read of the database, not a cached recalculation.
  • ๐Ÿ—ƒ๏ธ Three detail tables โ€” supplier contact directory, products joined with supplier and stock info, and products currently needing reorder. Nobody has to run a join to see the full picture; it's already assembled.
  • โž• Add New Product โ€” inserts the product and mirrors the initial stock as both a shipment record and a stock entry, in one stored procedure call. The person filling this form has no idea three tables just changed โ€” and that's the point. They shouldn't have to.
  • ๐Ÿ“œ Product History โ€” a unified timeline of every shipment and stock movement for a product, powered by a single SQL view merging two tables. The view exists so this timeline is defined once, in the database, instead of being re-joined by hand every time someone needs it.
  • ๐Ÿ” Place Reorder โ€” flags a product for restocking against its supplier, so nothing gets reordered against the wrong vendor.
  • โœ… Receive Reorder โ€” marks a reorder received, restocks the product, and logs the restock โ€” four table changes wrapped in one transaction. This is the highest-stakes action in the app: if it applied only partially, you'd have a reorder marked "received" while the shelf count never moved. The transaction makes that impossible.

๐ŸŽฎ How to Use

Basic Information

Live counts and values pulled straight from the database, plus supplier and product detail tables โ€” the person opening the dashboard sees the current state of things with zero setup.

Operational Tasks

Switch to Operational Tasks in the sidebar to choose one of four actions.

Add New Product โ€” fill in name, category, price, stock, reorder level, and supplier. Behind this one form: a product row, a shipment record, and a stock entry, all committed together.

Product History โ€” pick any product to see its full shipment and stock-entry timeline in one chronological list, not two tables the person has to mentally merge.

Place Reorder โ€” select a product and quantity to flag it for restocking.

Receive Reorder โ€” mark a placed reorder as received once stock physically arrives. One click; four tables update in lockstep behind it.


๐Ÿง  Data Flow

Streamlit UI (main.py)
        โ”‚
        โ–ผ
db_functions.py  โ”€โ”€โ–บ  MySQL (project_py_sql)
                              โ”‚
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ–ผ                   โ–ผ
          product_inventory_history   stored procedures
          (VIEW โ€” merges shipments    (AddNewProductManualID,
           + stock_entries)            MarkreorderAsRecieved)

The split here isn't arbitrary โ€” it mirrors risk. Reads (metrics, tables, dropdowns, history) can't leave the database inconsistent no matter how they're written, so they go through as plain parameterized SQL. Anything that writes to more than one table goes through a stored procedure instead, so the line in the code is drawn exactly where the actual danger is: multi-table writes, and only multi-table writes, are wrapped in a transaction.


๐Ÿ—„๏ธ SQL Logic

All SQL used by this project lives in sql/, kept separate from the app code so the logic that actually matters is easy to review on its own, without wading through UI code to find it:

  • sql/schema.sql โ€” table definitions, the product_inventory_history view, and both stored procedures
  • sql/queries.sql โ€” every query db_functions.py runs directly, organized by the function that uses it

๐Ÿ› ๏ธ Tech Stack

Technology Role Why It's Here
Python 3 Core language Glue between the UI and the database โ€” deliberately thin
Streamlit Dashboard UI Fast to build a form-based front end without writing HTML/JS
MySQL Data storage, stored procedures, views Where the actual logic and integrity guarantees live
mysql-connector-python Python โ†” MySQL connectivity Calls stored procedures and runs parameterized queries
Pandas Rendering query results as tables in the UI Turns query output into something a non-technical user can read

๐Ÿ—‚๏ธ Project Structure

Inventory-Supply-Chain-Dashboard/
โ”œโ”€โ”€ .streamlit/
โ”‚   โ””โ”€โ”€ secrets.toml.example     # template โ€” copy to secrets.toml locally
โ”œโ”€โ”€ datasets/                    # sample CSVs used to seed the database
โ”‚   โ”œโ”€โ”€ products.csv
โ”‚   โ”œโ”€โ”€ reorders.csv
โ”‚   โ”œโ”€โ”€ shipments.csv
โ”‚   โ”œโ”€โ”€ stock_entries.csv
โ”‚   โ””โ”€โ”€ suppliers.csv
โ”œโ”€โ”€ sql/
โ”‚   โ”œโ”€โ”€ schema.sql               # tables, view, stored procedures
โ”‚   โ””โ”€โ”€ queries.sql              # every query used by db_functions.py
โ”œโ”€โ”€ screenshots/                 # images used in this README
โ”œโ”€โ”€ db_functions.py              # all database access lives here
โ”œโ”€โ”€ main.py                      # Streamlit UI
โ”œโ”€โ”€ requirements.txt
โ”œโ”€โ”€ .gitignore
โ””โ”€โ”€ README.md

๐Ÿš€ Running Locally

Prerequisites

  • Python 3.10+
  • MySQL Server running locally

Steps

# Clone the repository
git clone https://github.com/Rushit004/InvenSQL.git
cd InvenSQL

# Create a virtual environment & install dependencies
python -m venv venv
venv\Scripts\activate        # Windows
# source venv/bin/activate   # macOS/Linux
pip install -r requirements.txt

# Set up the database
mysql -u root -p < sql/schema.sql
# then load the sample data from datasets/ into your tables

# Add your local MySQL credentials
mkdir .streamlit
copy .streamlit\secrets.toml.example .streamlit\secrets.toml
# edit secrets.toml with your MySQL host/user/password

# Run the app
streamlit run main.py

This app connects to a local MySQL instance and isn't deployed publicly โ€” several actions here (adding products, placing and receiving reorders) write directly to real data, so it's meant to be run and demoed locally rather than hosted with public write access.


๐Ÿ“ Design Notes

  • IDs are generated with SELECT MAX(id) + 1 inside each procedure, not AUTO_INCREMENT. This keeps ID assignment as a deliberate step inside the same transaction as the rest of the write, rather than an implicit side effect that happens outside the app's control. For a single-operator tool like this, that trade is worth it โ€” every ID the app hands out is one it can account for.
  • Multi-table writes are stored procedures, not sequential Python calls. A chain of INSERTs in Python has a gap between each call where a crash, a dropped connection, or a bad value leaves the database in a state nobody intended. A stored procedure wrapped in a transaction closes that gap entirely โ€” it's one commit, or none.

๐Ÿ’ญ Reflection

This project was never really about the UI. It was an exercise in figuring out where logic belongs โ€” and deciding, on purpose, that it didn't belong in Python. Every place where a naive version of this app would've chained together a few INSERT calls, I wrote a stored procedure instead. Every place I'd have re-joined the same two tables for the third time, I wrote a view once. The result is a small app that behaves like it should be trusted with someone else's real data โ€” because the person using it isn't going to be checking my work.


About the Author

Rushit Tholiya LinkedIn Profile

GitHub Profile

footer

About

A Streamlit dashboard for inventory and supply chain management, backed by MySQL stored procedures, transactions, and a unified history view for every multi-table operation.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages