You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A self-service ordering kiosk + complete bakery management platform β built for real shop operations.
π About
The Bakery Inventory & Kiosk System is a production-ready, full-stack web application that digitalises both the front-of-house and back-office operations of a small-to-mid-sized bakery. On the customer side, a large-screen self-service kiosk β styled like the ordering terminals at fast food chains β lets walk-in customers browse the menu, build their cart, and walk away with a token number in seconds, no cashier needed. On the owner side, a secure, JWT-protected dashboard gives complete control over the business: a live three-stage order pipeline, daily stock management that auto-disables sold-out products, custom wedding-cake orders with advance-payment tracking, raw material purchase logging, full price history records, and profit reports that calculate net income by subtracting daily expenses from completed-order revenue. Every price change is stored as a historical record rather than overwriting the old one, and every order permanently captures the price at time of sale β so financial reports are always accurate no matter how many times prices change in the future.
Owner needs to buy ingredients / packaging supplies
β
βΌ
βββββββββββββββββββββββββββ
β Ensure material exists β β POST /api/raw-materials (if new)
β in catalogue β e.g. "Refined Flour", "Butter"
β (RawMaterials page) β
ββββββββββββββ¬βββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β Log the purchase β β POST /api/raw-purchases
β (AddRawPurchase page) β Stores: material(ref), qty,
β β unitPrice, totalCost,
β β purchaseDate, status = PENDING
ββββββββββββββ¬βββββββββββββ
β
βΌ
βββββββββββββββ
β PENDING β β Ordered, not yet received
ββββββββ¬βββββββ
β Goods arrive β PATCH /api/raw-purchases/:id/done
βΌ
βββββββββββββββ
β DONE β β Confirmed received
β β β Cost recorded as expense for that date
β β β Feeds into daily expense report
βββββββββββββββ
7. Reporting Workflow
Owner opens Reports page β /reports
β
βββ Daily Profit Report ββββββββββββββββββββββββββββββββββββββ
β GET /api/reports/profit?date=YYYY-MM-DD β
β β
β Revenue = SUM of priceAtSale Γ qty (completed orders) β
β Expenses = SUM of totalCost (confirmed raw purchases) β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β Net Profit = Revenue β Expenses β
β β
βββ Date Range Profit Report βββββββββββββββββββββββββββββββββ€
β GET /api/reports/profit/range?start=...&end=... β
β β
β Same calculation across every day in the range β
β Useful for weekly / monthly / custom period reviews β
β β
βββ Daily Expense Report βββββββββββββββββββββββββββββββββββββ
GET /api/reports/expense?date=YYYY-MM-DD
Full breakdown of every confirmed raw purchase for the day
β¨ Features β All 18 Pages
π§ Customer-Facing Pages (Public β No Login Required)
#
Route
What It Does
1
/menu
Large-screen kiosk product grid. Shows all active products with Cloudinary images, current prices, and live stock status. Products with zero stock are hidden. Customers browse by category and add items to the cart.
2
/checkout
Cart review screen with quantity controls and a live running total. Customer enters their name and phone number. On confirmation, the order is submitted to the backend with priceAtSale locked per item.
3
Token number receipt screen displayed after a successful order. The large token number tells the customer what to quote at the counter when their order is ready. Also used by the owner as a read-only order summary list.
π Auth
#
Route
What It Does
4
/login
Owner login form. Sends credentials to POST /api/auth/login, receives a JWT token, stores it in localStorage, and redirects to the dashboard. All subsequent protected routes read this token from storage.
π Order Management
#
Route
What It Does
5
/dashboard
The owner's primary working view. Displays three live columns β Pending, Done, Completed β with action buttons on each order card. Completing an order triggers automatic stock deduction.
6
/orders
Full searchable and filterable history of all orders across all statuses. Useful for resolving disputes and reviewing past activity.
π¦ Product Management
#
Route
What It Does
7
/products
Active product catalogue. Each product card shows its image, name, category, current price, and enable/disable toggle. Soft-delete sends the product to the deleted list without breaking order history.
8
/add-product
Form to add a new product. The owner fills in name, category, and price, then uploads an image which passes through the image cropper for consistent aspect-ratio cropping before being sent to Cloudinary.
9
/deleted-products
Lists all soft-deleted products. Each entry has a Restore button that sets isDeleted: false and makes the product visible on the kiosk again. Order history referencing the product is always preserved.
π₯¦ Raw Material Management
#
Route
What It Does
10
/raw-materials
Full catalogue of all active raw materials used in the bakery. Shows name, unit of measure, and category. Links to add new entries and view deleted ones.
11
/add-raw-material
Form to register a new raw material in the catalogue before purchases can be logged against it. Captures name, unit (kg, litres, etc.), and category.
12
/deleted-raw-materials
Lists all soft-deleted raw materials with a restore button. Prevents orphaned purchase records by never hard-deleting materials that have purchase history.
π Raw Purchase Tracking
#
Route
What It Does
13
/raw-purchases
All logged raw material purchases with Pending/Done status, quantities, unit price, total cost, and purchase date. Confirmed (Done) purchases feed the daily expense report.
14
/add-raw-purchase
Form to log a new raw material purchase. The owner selects the material from the catalogue, enters quantity and unit price, and the total cost is calculated automatically.
π₯ Customer Management
#
Route
What It Does
15
/customers
All customers who have ever placed an order, grouped by phone number. Shows order count and total spend per customer. Useful for identifying loyal repeat customers.
16
/customers/:phone
Full order history for one specific phone number β every order placed, with date, items ordered, and amount paid. Useful for resolving customer queries.
π Reports & Custom Orders
#
Route
What It Does
17
/reports
Daily and date-range profit reports (revenue minus expenses) and daily expense breakdowns. Revenue figures use priceAtSale values from completed orders so historical reports are always accurate.
18
/add-custom-order
Form to create a bespoke order (wedding cakes, bulk event orders). Records customer details, order description, total agreed price, advance payment received, and outstanding balance due.
π Tech Stack
Technology
Purpose
Why Chosen
React.js 18
Frontend UI
Component model cleanly separates kiosk and dashboard into independent trees; hooks make cart state and form logic simple
React Router v6
Client-side routing
Declarative protected-route wrappers let /menu stay fully public while /dashboard and beyond require a valid JWT
Node.js 18
Backend runtime
Non-blocking I/O handles simultaneous order POSTs from the kiosk without queuing or blocking the owner's dashboard requests
Express.js 4
HTTP server and API
Minimal, unopinionated; thin route files delegate to controller files β concerns are cleanly separated throughout
MongoDB Atlas
Primary database
Document model accommodates the varied shapes of orders, custom orders, stock entries, and price history without schema migrations
Mongoose
MongoDB ODM
Schema validation, pre-save hooks (e.g. auto-disable on zero stock), and clean query syntax over the raw MongoDB driver
JWT
Owner authentication
Stateless token auth is ideal for a single-admin system; no session table needed, works seamlessly across Vercel + Render
Cloudinary
Image storage & CDN
Handles upload, optimisation, resizing, and global delivery β the Node server never serves a single static asset
ImageCropper
In-browser image crop
Ensures all product images are cropped to a consistent aspect ratio before upload, keeping the kiosk grid visually uniform
Vercel
Frontend hosting
Zero-config React deployment with automatic HTTPS and global edge CDN
Render
Backend hosting
Free-tier Node.js hosting with persistent environment variables and straightforward MongoDB Atlas connectivity
π Project Structure
INVENTORYSYSTEM/
β
βββ backend/
β β
β βββ controllers/ # Business logic β 12 files, one per domain
β β βββ authController.js # Validate credentials, issue JWT
β β βββ categoryController.js # Product category CRUD
β β βββ customerController.js # Aggregate orders grouped by phone number
β β βββ customOrderController.js # Create + PendingβDoneβCompleted flow for custom orders
β β βββ expenseReportController.js # Sum confirmed raw-purchase costs per date
β β βββ orderController.js # Place order (priceAtSale), status transitions, stock deduction
β β βββ productController.js # CRUD + Cloudinary upload + soft-delete + enable/disable
β β βββ productPriceController.js # Close old price record, open new; current-price query
β β βββ profitReportController.js # Revenue β expenses for day or date range
β β βββ rawMaterialController.js # Catalogue CRUD + soft-delete
β β βββ rawPurchaseController.js # Log purchase, confirm receipt β records as expense
β β βββ stockController.js # Daily stock entry, today's query, zero-stock disabling
β β
β βββ models/ # Mongoose schemas β shape of every MongoDB document
β β βββ Category.js # { name, description }
β β βββ CustomOrder.js # { customerName, phone, description, totalPrice, advancePaid, balanceDue, status }
β β βββ Order.js # { customerName, phone, tokenNumber, items[{product, name, qty, priceAtSale}], status }
β β βββ Product.js # { name, category, imageUrl, cloudinaryId, isEnabled, isDeleted }
β β βββ ProductPrice.js # { product, price, fromDate, toDate } β append-only history
β β βββ RawMaterial.js # { name, unit, category, isDeleted }
β β βββ RawPurchase.js # { material(ref), qty, unitPrice, totalCost, purchaseDate, status }
β β βββ StockEntry.js # { product(ref), date, quantityAdded, quantityRemaining }
β β βββ User.js # { email, password(hashed) } β single owner account
β β
β βββ routes/ # Express route definitions β thin, delegates to controllers
β β βββ authRoutes.js # POST /api/auth/login
β β βββ categoryRoutes.js # CRUD /api/categories
β β βββ customerRoutes.js # GET /api/customers GET /api/customers/:phone
β β βββ customOrderRoutes.js # CRUD + status /api/custom-orders
β β βββ expenseReportRoutes.js # GET /api/reports/expense
β β βββ orderRoutes.js # POST + GET + status PATCH /api/orders
β β βββ productPriceRoutes.js # POST + GET /api/prices
β β βββ productRoutes.js # Full product management /api/products
β β βββ profitReportRoutes.js # GET /api/reports/profit /api/reports/profit/range
β β βββ rawMaterialRoutes.js # CRUD /api/raw-materials
β β βββ rawPurchaseRoutes.js # CRUD + confirm /api/raw-purchases
β β βββ stockRoutes.js # GET today + POST update /api/stock
β β
β βββ middleware/
β β βββ authMiddleware.js # Verify JWT on every protected route, attach owner to req
β β βββ cloudinaryConfig.js # Initialise Cloudinary SDK + multer/upload config
β β
β βββ setup.js # One-time seed: creates default owner account
β βββ server.js # Entry point: connect MongoDB, mount routes, listen
β βββ package.json
β
βββ frontend/
β βββ src/
β β
β βββ pages/ # 18 full-page route components
β β β
β β β ββ CUSTOMER KIOSK (PUBLIC) ββββββββββββββββββββββββββ
β β βββ CustomerMenu.js # Product grid kiosk β browse, filter by category, add to cart
β β βββ Checkout.js # Cart review + name/phone entry + submit order
β β βββ OrdersSummary.js # Token number receipt (public) + order summary (owner)
β β β
β β β ββ AUTH βββββββββββββββββββββββββββββββββββββββββββββββ
β β βββ Login.js # Owner login form + JWT storage
β β β
β β β ββ ORDERS βββββββββββββββββββββββββββββββββββββββββββββ
β β βββ Dashboard.js # Live pipeline: Pending β Done β Completed
β β βββ Orders.js # Full historical order list, all statuses, searchable
β β β
β β β ββ PRODUCTS ββββββββββββββββββββββββββββββββββββββββββββ
β β βββ Products.js # Active catalogue with enable/disable/soft-delete
β β βββ AddProduct.js # Add product form β ImageCropper β Cloudinary upload
β β βββ DeletedProducts.js # Soft-deleted products with restore
β β β
β β β ββ RAW MATERIALS ββββββββββββββββββββββββββββββββββββββ
β β βββ RawMaterials.js # Active raw material catalogue
β β βββ AddRawMaterial.js # Add new raw material to catalogue
β β βββ DeletedRawMaterials.js # Soft-deleted materials with restore
β β β
β β β ββ RAW PURCHASES ββββββββββββββββββββββββββββββββββββββ
β β βββ RawPurchases.js # All logged purchases with Pending/Done status
β β βββ AddRawPurchase.js # Log a new raw material purchase
β β β
β β β ββ CUSTOMERS βββββββββββββββββββββββββββββββββββββββββ
β β βββ Customers.js # All customers grouped by phone, order count, spend
β β βββ CustomerDetails.js # Full order history for one phone number
β β β
β β β ββ REPORTS & CUSTOM ORDERS ββββββββββββββββββββββββββββ
β β βββ Reports.js # Profit + expense reports, daily and date-range
β β βββ AddCustomOrder.js # Bespoke order with advance payment tracking
β β
β βββ components/ # Reusable UI components
β β βββ Header.js # Owner dashboard nav bar with active route highlighting
β β βββ ImageCropper.js # In-browser aspect-ratio crop before Cloudinary upload
β β
β βββ App.js # Route table, JWT auth context, protected route logic
β βββ index.js # React DOM render entry point
β
βββ assets/
β βββ screenshots/ # Screenshot images (add yours here)
β
βββ .gitignore
# 1. Clone the repository
git clone https://github.com/iit2023271/INVENTORYSYSTEM.git
cd INVENTORYSYSTEM
# 2. Enter the backend directorycd backend
# 3. Install dependencies
npm install
# 4. Create your environment file and fill in values (see below)
cp .env.example .env
# 5. Start the development server
npm run dev
# API running at http://localhost:5000
Backend .env
Create backend/.env β every variable is required.
# ββ DATABASE βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ# MongoDB Atlas: mongodb+srv://<user>:<pass>@cluster.mongodb.net/<db># Local: mongodb://localhost:27017/bakeryMONGO_URI=mongodb+srv://your_user:your_password@cluster.mongodb.net/bakery# ββ AUTH βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ# Long random string used to sign JWTs β never commit this# Generate: node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"JWT_SECRET=your_super_secret_jwt_key_minimum_32_characters# ββ OWNER SETUP ββββββββββββββββββββββββββββββββββββββββββββββββββββββ# Passphrase checked by setup.js when seeding the owner accountOWNER_SECRET=your_owner_setup_passphrase# ββ SERVER βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββPORT=5000# ββ CLOUDINARY βββββββββββββββββββββββββββββββββββββββββββββββββββββββ# Found at cloudinary.com β Dashboard β Settings β API KeysCLOUDINARY_CLOUD_NAME=your_cloud_nameCLOUDINARY_API_KEY=your_api_keyCLOUDINARY_API_SECRET=your_api_secret
Frontend Setup
# From the project rootcd frontend
# Install dependencies
npm install
# Create environment file and fill in your backend URL
cp .env.example .env
# Start React dev server
npm start
# App opens at http://localhost:3000
Frontend .env
Create frontend/.env:
# ββ API URL βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ# Local development:REACT_APP_API_URL=http://localhost:5000# Production (replace with your Render URL after deploying the backend):# REACT_APP_API_URL=https://your-backend-name.onrender.com
First-Time Owner Account
The system enforces exactly one owner. Before logging into the dashboard, run the setup script once:
# From the backend/ directory
npm run setup
Default credentials created by the script:
Field
Value
Email
admin@shop.com
Password
admin123
β οΈChange the password immediately after first login. The script refuses to run a second time if an owner already exists β this prevents accidental overwrites in production.
1. Single Owner Account β Enforced at Architecture Level
The system is designed for one bakery operator, not a multi-tenant SaaS product. Rather than building role management and team-access features that would triple complexity without any business value here, the architecture enforces a hard constraint: setup.js refuses to create a second owner account if one already exists, and the login endpoint only ever issues tokens against that single record. This keeps authentication down to a standard JWT flow with no refresh tokens, no session tables, and no permission checks beyond "is this a valid owner token." If the business grows to need a team, the only change required is adding a role field to the User schema and a single middleware check β the foundation is already correct.
2. Daily Stock Entries Instead of a Running Inventory Counter
Most inventory systems maintain a running counter and decrement it on every sale. A bakery does not work that way β croissants are baked fresh every morning in specific quantities, and yesterday's unsold stock is written off or repurposed, not carried forward. The system models this reality by requiring the owner to enter fresh quantities each morning. If the owner forgets to enter stock, no product is shown as available with a stale count from a previous day. This also makes the stock entry ritual meaningful β it is the owner's daily signal to the system about what is available today, not a ledger correction.
3. Price History as Immutable Append-Only Records
When a price changes, the system closes the current ProductPrice record by setting its toDate to today, then creates a new record with fromDate set to today and toDate as null (signalling "currently active"). The old record is never updated or deleted. This means the full pricing timeline for every product is always queryable β you can find exactly what a product cost on any date in the past. It provides an automatic audit trail, makes the priceAtSale pattern reliable (below), and costs virtually nothing in storage since price changes are infrequent relative to orders.
4. priceAtSale Stored Directly on Every Order Line Item
When an order is placed, the backend looks up the currently active price for each product and stores it directly on the order document as priceAtSale. This makes every order a self-contained financial record β it knows what was sold, how many units, and exactly what was charged at that moment in time. Without this, any profit calculation for a past period would silently recalculate using today's prices rather than the prices actually charged, making historical reports unreliable. This is standard practice in every serious commerce system and is just as important for a small bakery as it is for a large e-commerce platform.
5. Soft Delete for Products and Raw Materials
Deleting a product or raw material sets an isDeleted: true flag rather than removing the document. This is essential for referential integrity: every Order references product IDs in its line items, and every RawPurchase references a raw material ID. A hard delete would orphan those references and make historical records unreadable. Soft delete preserves the full history, allows the owner to restore an item deleted by mistake, and costs nothing in query performance because all normal listing queries simply filter on isDeleted: false. The dedicated Deleted Products and Deleted Raw Materials pages give the owner complete visibility and control.
6.Everything is Mobile Friendl
Everyting can be controlled in the mobile itself.so this is the biggest advantage. assuming owner doesnt know any technical knowledge, this website is made for them.
Built this system to solve a real operational problem: replacing the paper-and-shouting workflow of a busy bakery counter with a clean digital kiosk and owner dashboard β from customer token to end-of-day profit report.
π License
This project is licensed under the MIT License.
MIT License
Copyright (c) 2025 iit2023271
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Made with β, flour, and way too many console.log statements.
β Star this repo if it helped you β it takes one click and means a lot.