Skip to main content

Product Domain Module

The polymorphic catalog engine powering CRUD operations, category‑specific validation, and Cloudinary image management for the Reshma‑Core platform.

MongoDB Cloudinary Zod Mongoose


1. Overview

The Product Module (src/modules/products/) is the core catalog engine. It handles CRUD operations for the polymorphic inventory, validates category‑specific payloads using Zod discriminated unions, and manages the Cloudinary image pipeline (memory‑stream uploads, automatic rollback on failure). It also synchronises product data to Typesense for fast search.

Base Route: /api/v1/products


2. Controller Architecture & API Endpoints

The presentation layer is split into two controllers to enforce security boundaries and keep files maintainable.

Public Controller (PublicProductController)

Optimised for read‑heavy traffic. Uses MongoDB compound indexes, text search, and .lean() to strip Mongoose hydration overhead.

MethodEndpointDescription
GET/Fetch paginated catalog. Supports page, limit, itemType, mainCategory, subCategory, and full‑text search (q).
GET/:idFetch a single product by ObjectId.

Both routes are wrapped in cacheMiddleware(300) (5‑minute TTL) and protected by standardLimiter.

Admin Controller (AdminProductController)

Requires a valid JWT and the ADMIN role (enforced by protect + restrictTo("ADMIN")).

MethodEndpointDescription
POST/Create a new product (multipart/form‑data, up to 5 images).
PATCH/:idPartially update product fields.
DELETE/:idSoft‑delete a product (isActive: false). Hard deletion never occurs to preserve historical orders.

After each mutation, a fire‑and‑forget cache invalidation (CacheManager.invalidateCachePattern) clears the Redis edge cache.


3. Zod Validation Strategy (Discriminated Unions)

The admin creation endpoint uses z.discriminatedUnion to enforce the correct fields based on itemType. Defined in product.admin.dto.ts.

export const CreateProductSchema = z.object({
body: z.discriminatedUnion("itemType", [
BangleSchema,
ApparelSchema,
FabricSchema,
InnerwearSchema,
AccessorySchema,
]),
});

How it protects the system:

  • If itemType === "BANGLE", Zod requires bangleSizes and forbids cupSizes.
  • If itemType === "APPAREL", Zod requires sizes and forbids bangleSizes.
  • All types must include hsnCode and taxProfile (legal GST requirement).

Invalid requests are rejected with 400 Bad Request before reaching the service layer.


4. Business Logic & Service Layer (product.service.ts)

The service layer isolates database operations and handles distributed transactions. Below is the product creation flow with Cloudinary rollback.

Key service methods:

MethodDescription
createProductUploads images to Cloudinary, saves product, rolls back images on DB failure.
updateProductPartially updates product, syncs changes to Typesense (if isActive toggled).
softDeleteProductSets isActive: false, removes from Typesense index.
getProductsPaginated, filtered catalog with text search.
reserveStockAtomic $inc with $gte – used during checkout to prevent overselling.

Every product stores:

  • hsnCode – 4‑8 digit numeric string (e.g., "7117" for imitation jewellery).
  • taxProfile – enum used by the TaxEngine (e.g., "STITCHED_APPAREL", "UNSTITCHED_FABRIC").

The tax engine dynamically resolves the GST rate based on the transaction value (post‑discount). For STITCHED_APPAREL, the rate changes from 18% to 5% if the discounted price falls below ₹2,500.


6. Edge Cache & Performance Shielding

FeatureImplementationBenefit
Redis edge cachecacheMiddleware(300) on all GET routes.Serves JSON from RAM (~2ms) for 5 minutes. 10,000 concurrent users → only 1 MongoDB query.
Cache invalidationCacheManager.invalidateCachePattern fired after admin mutations.Ensures public catalog sees fresh data immediately.
Typesense DLQFailed syncs go to search-sync-queue (BullMQ) with 10 attempts, exponential backoff (5s, 10s, 20s…).Guarantees eventual consistency without blocking primary DB transaction.

7. Security & Validation Firewalls

ThreatMitigation
NoSQL injectionZod schemas + Sanitizer.sanitize() strips $ and . keys.
Prototype pollutionSanitizer.PROHIBITED_KEYS removes __proto__, constructor, prototype.
Mass assignmentZod schemas only allow documented fields; extra fields are stripped.
Malicious image uploadsMulter MIME filter (only JPEG/PNG/WebP), 10MB limit, Cloudinary re‑encodes.
DoS (public catalog)standardLimiter (100 req/15 min) + edge cache.
Admin RBACrestrictTo("ADMIN") on all write endpoints.

FilePurpose
src/modules/products/product.admin.controller.tsAdmin CRUD, cache invalidation.
src/modules/products/product.public.controller.tsPublic listing and detail.
src/modules/products/product.service.tsCore logic – creation, update, stock reservation, search sync.
src/modules/products/models/base-product.model.tsMongoose base schema, indexes, pre‑delete hook.
src/modules/products/models/*.model.tsDiscriminator models (bangle, apparel, fabric, innerwear, accessory).
src/modules/products/interfaces/*.tsTypeScript interfaces for base and discriminators.
src/modules/products/dtos/product.admin.dto.tsZod discriminated union for creation/update.
src/modules/products/dtos/product.public.dto.tsQuery validation (pagination, filters).
src/shared/middlewares/cache.middleware.tsRedis edge cache.
src/shared/middlewares/upload.middleware.tsMulter memory storage, file filter.
src/config/cloudinary.tsUpload/delete utilities.
src/shared/queues/export.queue.ts (search sync)Dead‑letter queue for Typesense retries.

9. See Also


The Reshma-Core Team