The Core Concept: Inventory Tracking Types
The Core Concept: Inventory Tracking Types
The key insight is that products don't differ by category (fruits vs laptops), they differ by how their stock is tracked. There are exactly 5 tracking behaviors that cover virtually every physical product on earth:
1. 📦 Simple Quantity (Count-Based)
- Stock = a number. Sell one, subtract one.
- Example: A packaged box of Wai Wai noodles, a bottle of Coke, a keyboard
- This is what 90% of e-commerce systems do by default
2. ⚖️ Weighted / Measured (Unit-Based)
- Stock tracked in kg, liters, meters — not "count"
- When a customer buys 500g of rice, you deduct 0.5kg from your 50kg stock
- Example: Loose rice, spices, fabric, cooking oil sold loose
3. 🧪 Batch / Lot Tracked (Perishables)
- Stock is grouped into batches, each with an expiry date
- You might have 3 batches of milk: Batch A (expires June 20), Batch B (expires June 25)
- System enforces FIFO (First In, First Out) — sell the oldest batch first
- Example: Milk, yogurt, meat, medicine, fruits & vegetables
4. 🔢 Serialized (Individual Unit Tracking)
- Every single item has a unique serial number / IMEI
- You don't just know "we have 5 laptops" — you know which 5 laptops
- Enables warranty tracking, returns per unit, theft detection
- Example: Laptops, phones, cameras, expensive jewelry
5. 📋 Catalog-Only (No Stock Tracking)
- Just a menu. No inventory math at all.
- Vendor manually toggles "Available" / "Unavailable"
- Example: Restaurant dishes, bakery items baked daily, services (haircuts, repairs), made-to-order items
The Grocery Store Question (You're Right!)
Your instinct is spot-on. Nobody opens a carton of biscuits and scans each one. Here's what professional systems actually do:
- Large retailers (Big Mart, Bhat-Bhateni): They use barcode POS scanning at checkout. Each scan deducts 1 from a bulk count. They do periodic physical inventory counts to reconcile.
- Small grocery shops: They use Catalog-Only mode or a simple count. They reorder when the shelf looks empty (called Par Level system). No per-item tracking.
- The pragmatic answer for Khoji Nepal: Let the vendor choose. A grocery store owner can list Wai Wai Noodles as a catalog item (available/unavailable) or as simple quantity ("I have ~200 packets"). Both are valid.
What About Variants? (Size, Color, Flavor)
Variants are separate from tracking type. A single product can have variants, and each variant has its own stock:
Product: "Nike Running Shoes"
├── Variant: Red / Size 8 → Stock: 12 (simple quantity)
├── Variant: Red / Size 9 → Stock: 8
├── Variant: Blue / Size 8 → Stock: 5
└── Variant: Blue / Size 9 → Stock: 0 (out of stock)
Each variant gets its own SKU (Stock Keeping Unit) — a unique code.
Composite / Recipe Products (Bonus)
Some products are made from ingredients. When you sell 1 burger, the system deducts:
- 1 bun from bun inventory
- 1 patty from meat inventory
- 2 lettuce leaves from produce inventory
This is called Bill of Materials (BOM) and is critical for restaurants and bakeries. It connects catalog-only menu items to actual ingredient inventory.
The Architecture: NOT Microservices
Should we create separate microservices for different product categories?
No! That would be massively over-engineered. You'd have to coordinate between services for orders, payments, search — it becomes a nightmare.
The correct approach is a single product & inventory system with a tracking_type field on each product:
Product
├── name, description, images, price
├── tracking_type: "simple" | "weighted" | "batch" | "serialized" | "catalog_only"
├── unit: "piece" | "kg" | "liter" | "meter" (for weighted)
├── has_variants: boolean
└── Variants[] (optional)
├── sku, price_override, attributes (color, size, etc.)
└── InventoryRecords[]
├── quantity / weight
├── batch_number (if batch)
├── expiry_date (if batch)
└── serial_number (if serialized)
The UI adapts based on tracking_type:
- If
simple→ show a quantity input - If
weighted→ show a weight input with unit selector - If
batch→ show batch form with expiry date picker - If
serialized→ show serial number entry field - If
catalog_only→ show just an availability toggle
This is exactly how professional systems like Odoo, ERPNext, Lightspeed, and Square handle it. One system, adaptive behavior.
Summary Table
| Tracking Type | Stock Unit | Expiry? | Per-Item ID? | Example |
|---|---|---|---|---|
| Simple Quantity | Count | ❌ | ❌ | Packaged snacks, keyboards |
| Weighted | kg/liter/meter | ❌ | ❌ | Loose rice, fabric, oil |
| Batch/Lot | Count or Weight | ✅ | Per batch | Milk, fruits, medicine |
| Serialized | Individual | ❌ | ✅ (serial #) | Laptops, phones, jewelry |
| Catalog Only | None | ❌ | ❌ | Restaurant dishes, services |
What This Means for Khoji Nepal
When a vendor registers a product, we simply ask them: "How do you track this item?" and present friendly options like:
- "I count individual pieces" → Simple
- "I sell by weight/volume" → Weighted
- "It has an expiry date" → Batch
- "Each item has a serial number" → Serialized
- "I just want to list it (no stock tracking)" → Catalog Only
This single design handles a fruit seller, a laptop shop, a restaurant, AND a grocery store — all within one system, no microservices needed.
Want me to start designing the database schema and Laravel models for this unified product/inventory system?