The 4 Fundamental Product Archetypes
The Core Problem
You're not really dealing with "different products." You're dealing with different inventory behaviors. A tomato and a laptop are both "products," but how you track, sell, expire, and replenish them is fundamentally different.
The 4 Fundamental Product Archetypes
In inventory management theory, all products fall into one of these categories:
1. Serialized / Durable Goods
Laptops, phones, furniture, jewelry
- Each individual unit has a unique identity (serial number, IMEI)
- You track each item — "I have 3 laptops: SN-001, SN-002, SN-003"
- They don't expire
- Returns matter at the individual unit level
- Inventory model:
Stock = count of individual tracked units
2. Non-Serialized / Counted Goods
T-shirts, shoes, mugs, keychains, handicrafts
- Units are interchangeable — one red T-shirt (size M) is the same as another
- You don't track individual items, just quantity per variant (color, size)
- They don't expire (or expire very slowly)
- This is the "classic" e-commerce model (what Shopify does)
- Inventory model:
Stock = integer count per SKU/variant
3. Perishable Goods
Fruits, vegetables, dairy, meat, flowers, bakery items
- Units are interchangeable like counted goods, BUT...
- They have an expiry/best-before date
- Stock value degrades over time (a banana worth ₹10 today might be ₹5 tomorrow)
- You track stock in batches — "I received 50 kg of tomatoes on June 15, expires June 20"
- Requires FIFO (First In, First Out) — sell the oldest stock first
- Inventory model:
Stock = sum of (quantity × batch), each batch has an expiry
4. Bulk / Unmeasured Goods (Grocery/FMCG)
Noodles, biscuits, chocolates, rice, oil, spices
- This is exactly the case you described — "nobody opens a carton to track individual packets"
- Stock is tracked at the carton/case level, not individual units
- Sold individually but restocked in bulk
- Often uses par-level reordering — "when I have fewer than 10 packets, reorder a carton of 48"
- Inventory model:
Stock = quantity (units), Reorder in = bulk units (cartons/cases)
How Real Platforms Handle This
Here's the key insight: You do NOT build separate microservices for each type. That's a trap.
Instead, you build one flexible product/inventory system with a concept called "Inventory Strategies" or "Stock Policies".
┌─────────────────────────────────────────────────┐
│ Product │
│ name, description, images, price, category │
│ │
│ inventory_type: SERIALIZED | COUNTED | │
│ PERISHABLE | BULK │
└────────────────────┬────────────────────────────┘
│
┌──────────┼──────────────┐
│ │ │
┌─────▼────┐ ┌───▼───┐ ┌──────▼──────┐
│ Variants │ │ Stock │ │ Batches │
│(size, │ │(qty, │ │(qty, expiry,│
│ color) │ │ sku) │ │ received_at)│
└──────────┘ └───────┘ └─────────────┘
The Unified Model
Every product has:
- Base product info (name, images, description, category)
- An inventory type (one of the 4 above)
- Variants (optional — size, color, weight, flavor)
- Stock records (the actual quantity tracking)
The inventory type determines the behavior, not the data structure:
| Behavior | Serialized | Counted | Perishable | Bulk |
|---|---|---|---|---|
| Track individual units? | ✅ Yes | ❌ No | ❌ No | ❌ No |
| Has variants? | Sometimes | Usually | Rarely | Rarely |
| Has expiry? | ❌ No | ❌ No | ✅ Yes | Sometimes |
| Batch tracking? | ❌ No | ❌ No | ✅ Yes (FIFO) | Optional |
| Reorder in bulk? | ❌ No | Optional | ✅ Yes | ✅ Yes |
| Unit of measure | each | each | kg/liter/each | each (sold) / carton (stocked) |
| Stock degrades? | ❌ No | ❌ No | ✅ Yes | ❌ No |
How This Maps to Your App
For Khoji Nepal, here's how this applies practically:
- A handicraft vendor sells counted goods → simple quantity tracking
- A fruit/veggie vendor sells perishable goods → batch tracking with expiry, FIFO selling
- A grocery store sells bulk/FMCG goods → simple quantity, reorder thresholds
- An electronics shop sells serialized goods → individual unit tracking with serial numbers
- A bakery sells perishable goods → batch tracking, short expiry windows
- A clothing store sells counted goods with variants → quantity per size/color combo
All of these live in the same products and inventory tables. The inventory_type field on the product determines which dashboard UI the vendor sees, which stock deduction logic runs, and which alerts fire.
Why NOT Microservices for This
Microservices would mean:
- Separate databases for fruits vs electronics vs clothing
- Separate APIs, separate deployments, separate bugs
- A customer searching "gift basket" that contains fruits + a mug + a t-shirt would need to query 3 separate services
- Cross-category orders become a nightmare
Instead, use a single monolith (your Laravel app) with a Strategy Pattern — one InventoryService that delegates to the right stock deduction logic based on the product's inventory_type.
Summary
| ❌ Don't Do | ✅ Do Instead |
|---|---|
| Separate microservices per category | One unified product system with an inventory_type field |
| Different tables for different products | Same products table, different behavior via strategy pattern |
| Track every noodle packet individually | Track quantity, restock in cartons |
| Ignore expiry for perishables | Batch tracking with FIFO and expiry alerts |
| Build a custom system from scratch | Follow the 4 archetypes above as your foundation |
This is the fundamental theory. When we're ready to implement, we'd design the Laravel database schema with products, product_variants, inventory_stocks, and inventory_batches tables — all in one service, with the inventory_type driving the behavior.
Want me to dive deeper into any of these archetypes, or shall we start designing the actual database schema for this?