Chapter 25 min read

The Core Insight: Don't Think by "Category" — Think by "Tracking Behavior"

The Core Insight: Don't Think by "Category" — Think by "Tracking Behavior"

Your instinct to separate fruits from laptops is correct, but the separation isn't by what the product is — it's by how the product is tracked and sold. This is a critical distinction.

There are really only 5 fundamental inventory tracking behaviors. Every product in the world falls into one (or sometimes a combination) of these:


1. Unit-Tracked (Serialized) Inventory

"Each individual item has its own identity"

Examples: Laptops, phones, motorcycles, jewelry, cameras

How it works: Every single item gets a unique serial number. When you sell "a laptop", you're selling that specific laptop (Serial #ABC123). You know exactly which unit the customer received.

Why: Warranty tracking, returns, theft prevention, resale value.

Stock: quantity = COUNT of unsold serial numbers


2. Unit-Tracked (Non-Serialized) Inventory

"We count individual items, but they're all interchangeable"

Examples: Noodle packets, biscuit packs, bottled drinks, packaged snacks, shampoo bottles

How it works: You track quantity — "I have 200 packets of Wai Wai noodles" — but you don't care which specific packet the customer gets. They're all identical. You mentioned nobody opens the carton to track individual biscuit packets — exactly right. You track at the sellable unit level.

Stock: quantity = a number you increment/decrement

This is what you're calling "grocery" — and you're correct that it's simple counting. No one tracks serial numbers on a packet of Kurkure.


3. Weight/Measure-Based (Bulk) Inventory

"Sold by weight, volume, or length — not by piece"

Examples: Rice (per kg), cooking oil (per litre), fabric (per meter), spices, loose tea, fruits, vegetables

How it works: You don't sell "1 item of rice". You sell "2 kg of rice". Stock is tracked in weight or volume, not quantity. When a customer buys 500g of tomatoes, you subtract 0.5 from your kg stock.

Stock: quantity = 45.5 kg remaining (decimal, not integer)

Special challenge: Shrinkage — 100 kg of tomatoes today might be 95 kg tomorrow just due to water loss. This is called natural wastage and you need to account for it.


4. Perishable Inventory (with Expiry)

"This product has a limited shelf life and will become unsellable"

Examples: Milk, yogurt, bread, meat, fresh flowers, medicines

How it works: Same as types 2 or 3 above, BUT with an added dimension: expiry date. You must sell older stock first (FIFO — First In, First Out). Stock that expires becomes a write-off (a loss).

Stock: quantity = 50 units, BUT 20 expire tomorrow, 30 expire next week

This is actually a modifier on types 2 or 3, not a separate type. Milk is "unit-tracked + perishable". Tomatoes are "weight-based + perishable".


5. Made-to-Order / Prepared Items

"This product doesn't exist until the customer orders it"

Examples: Restaurant food (momo, pizza), custom cakes, tailored clothing, custom furniture

How it works: You don't track stock of "momos" — you track stock of the ingredients (flour, meat, spices). When someone orders 1 plate of momos, you deduct the raw ingredients. The finished product is created on demand.

Stock: You track raw material inventory, not finished goods. This is called BOM (Bill of Materials) or Recipe Management.


So What's the Architecture?

Here's the key: You do NOT need microservices for each type. That would be massive over-engineering. Instead, you need a single flexible product system with a "Product Type" field that controls the behavior.

Think of it like this:

┌─────────────────────────────────────────────┐
│              PRODUCT (base)                 │
│  - name, description, images, price         │
│  - vendor_id, category_id                   │
│  - product_type: ENUM                       │
│    ├── UNIT_SERIALIZED   (laptops)          │
│    ├── UNIT_COUNTED      (noodle packets)   │
│    ├── WEIGHT_BASED      (rice, tomatoes)   │
│    └── MADE_TO_ORDER     (momos, pizza)     │
│                                             │
│  - is_perishable: boolean                   │
│  - unit_of_measure: "piece"|"kg"|"litre"|…  │
│  - track_expiry: boolean                    │
├─────────────────────────────────────────────┤
│              VARIANTS                        │
│  (for products with options)                │
│  - size, color, weight_option               │
│  - sku, barcode                             │
│  - price_override                           │
├─────────────────────────────────────────────┤
│              STOCK ENTRIES                   │
│  - variant_id                               │
│  - quantity (decimal for weight-based)       │
│  - batch_number (optional)                  │
│  - expiry_date (if perishable)              │
│  - serial_number (if serialized)            │
│  - cost_price (for profit tracking)         │
├─────────────────────────────────────────────┤
│         INGREDIENTS / BOM                    │
│  (only for MADE_TO_ORDER products)          │
│  - product_id (the finished dish)           │
│  - ingredient_product_id (raw material)     │
│  - quantity_needed                           │
└─────────────────────────────────────────────┘

The product_type field is what controls the entire UI and business logic:

  • If UNIT_SERIALIZED → show serial number input when adding stock
  • If WEIGHT_BASED → show kg/litre input instead of quantity
  • If is_perishable → show expiry date picker, enable FIFO alerts
  • If MADE_TO_ORDER → show recipe/ingredient builder, no stock count

What About Variants?

A "variant" is when the same product comes in different options. This applies to ALL types:

ProductVariant DimensionExample
T-shirtSize + ColorRed/M, Blue/L
RiceWeight option1kg bag, 5kg bag, 25kg sack
LaptopRAM + Storage8GB/256GB, 16GB/512GB
MomoTypeSteam, Fried, Jhol

Each variant gets its own SKU and its own stock count. But they all belong to one parent product.


Your Key Takeaway

You need ONE product system with behavior flags, not separate microservices. The magic is in the product_type + is_perishable + unit_of_measure fields. These 3 fields alone determine 90% of how inventory works for any product in existence.

The vendor's dashboard UI will adapt dynamically based on these flags — showing different forms, different stock views, and different alerts depending on what type of product they're managing.


Want me to dive deeper into any of these areas, or shall we start designing the database schema for this flexible product system?

    The Core Insight: Don't Think by "Category" — Think by "Tracking Behavior" — Product management suggestions | Krishna Tiwari