Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/fredy-rizo/ecommerce-delivery/llms.txt

Use this file to discover all available pages before exploring further.

The Ecommerce Delivery API stores all user-generated images — product photos, user avatars, and payment proof screenshots — in a Google Cloud Storage bucket. Multer stages each upload to a local storage/ subdirectory first; Sharp then re-encodes the file to WebP at the correct dimensions before it is streamed to the bucket. The public HTTPS URL returned by Cloud Storage is what gets persisted in MongoDB.

Required environment variable

One environment variable controls which bucket receives uploaded images. Set it in your .env file:
NAMEGOOGLECLOUD
string
required
The name of the Cloud Storage bucket that receives all uploaded images, for example my-ecommerce-bucket. The bucket must exist in your Google Cloud project before the server starts.
The API authenticates to Google Cloud Storage using a service account JSON key file (ecommerce-467123-55f9c79a002a.json) placed alongside cloudStorage.js. You must download this file from the Google Cloud Console (IAM & Admin → Service Accounts → Keys) and add it to src/middleware/utils/ before running the server. The file must be excluded from version control.

Local staging directories

Before any file reaches Cloud Storage it is saved to disk by Multer. The API uses three separate staging directories, one per resource type:
DirectoryUsed for
storage/userUser avatar uploads
storage/productProduct image uploads
storage/salePayment proof image uploads
These directories are referenced directly in the route files via multer.diskStorage. Create them in the project root if they do not already exist:
mkdir -p storage/user storage/product storage/sale

How cloudStorage.js works

src/middleware/utils/cloudStorage.js initialises a @google-cloud/storage client using the project ID and the service account credentials file, then exports a reference to the target bucket:
import { Storage } from "@google-cloud/storage";
import ksyFilename from "./ecommerce-467123-55f9c79a002a.json" with { type: "json" };
import config from "../../config.js";

let projectId = "ecommerce-467123";
let keyFilename = "ecommerce-467123-55f9c79a002a";

const storage = new Storage({
  projectId,
  keyFilename,
  credentials: ksyFilename,
});

const bucket = storage.bucket(config.NAMEGOOGLECLOUD);
export { bucket };
The exported bucket object is imported by process.js and used for all upload operations.

Image processing with Sharp

Before uploading, process.js uses Sharp to resize each image to the appropriate dimensions and re-encode it as WebP at 70% quality. The target dimensions depend on the field name passed to imageGenerate:
Field nameWidthHeightUsed for
avatar250 px250 pxUser profile picture
imgPay779 px1,600 pxPayment proof image
productImg800 px800 pxProduct listing image
publication400 px400 pxPublication image
voucher350 px350 pxVoucher image

Image upload flow

1

Client sends a multipart/form-data request

The client POSTs a file (e.g. avatar, productImg, or imgPay) to the relevant API endpoint. Express receives the request and passes it through the Multer middleware.
2

Multer writes the raw file to disk

Multer’s diskStorage engine saves the incoming file to the appropriate staging directory — storage/user, storage/product, or storage/sale — with a random numeric prefix added to the original filename to avoid collisions.
3

imageGenerate processes and uploads each file

The route controller calls imageGenerate(files, fieldName) from process.js. For each file Multer staged, the function:
  1. Determines the correct output dimensions based on fieldName.
  2. Runs Sharp on the staged file — resizing to the target dimensions and encoding as WebP at 70% quality — writing the result to the same staging directory.
  3. Calls the internal uploadImage() helper, which streams the processed WebP file to the Cloud Storage bucket with a timestamp-based destination name.
  4. Constructs and returns a public URL in the form https://storage.googleapis.com/<NAMEGOOGLECLOUD>/<timestampedFilename>.
4

URLs and cleanup paths are returned to the controller

imageGenerate returns an object containing the uploaded image URL(s) under the field name key, plus a deleteFiles array listing every local staging path that should be removed. The controller stores the URLs in MongoDB and calls deleteImages(deleteFiles) to clean up the temporary files from disk.
5

Temporary local files are deleted

deleteImages iterates the deleteFiles array, normalises each path, and calls fs.unlinkSync() on files that still exist. This keeps the storage/ directories clear between requests.

Key functions in process.js

// Upload a single processed image to Cloud Storage
// Returns { imageLink: "<public-url>" }
export const uploadImage = async (image, name) => { ... };

// Delete an array of local file paths
export const deleteImages = (files) => { ... };

// Orchestrate resizing, uploading, and cleanup path collection
// fieldName: string | string[]  — e.g. "avatar" or ["productImg"]
// Returns { [fieldName]: imageObjects[], deleteFiles: string[] }
export const imageGenerate = async (files, fieldName) => { ... };

Firebase Admin SDK

The project also includes a Firebase Admin SDK initialisation in src/middleware/firebase/firebase.js. This is used exclusively for sending push notifications via Firebase Cloud Messaging and is entirely independent of the Google Cloud Storage pipeline. See Notifications for details.

Build docs developers (and LLMs) love