Overview
Theproducts collection stores the complete product catalog with support for color/capacity variants, pricing, inventory tracking, and promotional flags.
Collection Path
products/{productId}
Document Schema
Show Basic Information
Show Basic Information
Show Pricing
Show Pricing
Show Inventory
Show Inventory
Show Media
Show Media
Show Variants
Show Variants
True if product has color variants
Array of color variants with images:
[
{
color: 'negro',
images: ['url1.jpg', 'url2.jpg']
}
]
True if product has capacity/storage options
Array of capacity options:
[
{ label: '128GB', price: 4500000 },
{ label: '256GB', price: 5000000 }
]
Stock tracking for color+capacity combinations:
[
{
color: 'negro',
capacity: '256GB',
price: 5000000,
stock: 5
}
]
Show Status & Flags
Show Status & Flags
active or inactive (only active products appear in catalog)Featured in “Weekly Choices” section
Display in hero banner slider
Show in “New Arrivals” banner
Custom banner image URL for hero slider (optional)
Custom banner image for launch section (optional)
Example Document
{
"name": "iPhone 14 Pro",
"category": "Celulares",
"subcategory": "Apple",
"brand": "Apple",
"description": "<p>iPhone con chip A16 Bionic y cámara de 48MP</p>",
"price": 4500000,
"originalPrice": 5000000,
"cost": 3800000,
"promoEndsAt": "2026-03-15T23:59:59Z",
"stock": 15,
"minStock": 3,
"sku": "APL-IP14P-256",
"mainImage": "https://storage.googleapis.com/pixeltech/iphone14pro.jpg",
"images": [
"https://storage.googleapis.com/pixeltech/iphone14pro-2.jpg",
"https://storage.googleapis.com/pixeltech/iphone14pro-3.jpg"
],
"hasVariants": true,
"variants": [
{
"color": "negro",
"images": ["https://.../negro-1.jpg"]
},
{
"color": "plateado",
"images": ["https://.../plateado-1.jpg"]
}
],
"hasCapacities": true,
"capacities": [
{ "label": "128GB", "price": 4200000 },
{ "label": "256GB", "price": 4500000 },
{ "label": "512GB", "price": 5200000 }
],
"combinations": [
{ "color": "negro", "capacity": "256GB", "price": 4500000, "stock": 8 },
{ "color": "plateado", "capacity": "256GB", "price": 4500000, "stock": 7 }
],
"status": "active",
"isWeeklyChoice": true,
"isHeroPromo": false,
"isNewLaunch": false,
"createdAt": "2026-01-15T10:30:00Z",
"updatedAt": "2026-03-05T14:22:00Z"
}
Queries
Get All Active Products
const snapshot = await db.collection('products')
.where('status', '==', 'active')
.get();
Get Products by Category
const snapshot = await db.collection('products')
.where('status', '==', 'active')
.where('category', '==', 'Celulares')
.orderBy('name', 'asc')
.get();
Get Weekly Featured Products
const snapshot = await db.collection('products')
.where('isWeeklyChoice', '==', true)
.where('status', '==', 'active')
.get();
Get Low Stock Products
const snapshot = await db.collection('products')
.where('stock', '<=', db.collection('products').doc().data().minStock)
.get();
Get Updated Products (Delta Sync)
Used by SmartProductSync:const lastSyncTime = new Date(1709647200000); // User's last visit
const snapshot = await db.collection('products')
.where('updatedAt', '>', lastSyncTime)
.get();
Variant Pricing Logic
When a product has both colors and capacities:-
Check
combinationsarray first:const combo = product.combinations.find(c => c.color === selectedColor && c.capacity === selectedCapacity ); const price = combo ? combo.price : product.price; -
Fallback to
capacitiesarray:if (!combo && product.capacities) { const cap = product.capacities.find(c => c.label === selectedCapacity); const price = cap ? cap.price : product.price; } -
Default to base price:
const price = product.price;
Stock Management
Deducting Inventory
When an order is paid, stock is deducted from both global and variant-specific stock:// Global stock
let newStock = product.stock - orderItem.quantity;
// Variant stock (if applicable)
if (orderItem.color || orderItem.capacity) {
const idx = product.combinations.findIndex(c =>
c.color === orderItem.color && c.capacity === orderItem.capacity
);
if (idx >= 0) {
product.combinations[idx].stock -= orderItem.quantity;
}
}
await productRef.update({
stock: newStock,
combinations: product.combinations
});
Triggering Updates
Critical: Always update
updatedAt when modifying products to trigger SmartProductSync delta updates.await productRef.update({
stock: newStock,
updatedAt: admin.firestore.FieldValue.serverTimestamp()
});
Security Rules
Recommended Firestore security rules:match /products/{productId} {
// Allow public read for active products
allow read: if resource.data.status == 'active';
// Only admins can write
allow write: if request.auth != null &&
get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
Indexes
Required composite indexes:// Category + Status
products: [category ASC, status ASC]
// Updated timestamp (for delta sync)
products: [updatedAt DESC, status ASC]
// Promo flags
products: [isHeroPromo ASC, status ASC]
products: [isNewLaunch ASC, status ASC]
products: [promoEndsAt ASC]