Quickstarters
How to Build an E-Commerce Backend?
88 min
in this hands on tutorial, you’ll create a rock solid, full stack e commerce application from the ground up using a backend as a service along the way, you’ll master secure user authentication, ensuring only authorized shoppers and admins gain access intuitive data models, designed to power product catalogs, customer profiles, and order histories restful and real time apis, so your frontend always stays in sync with inventory, carts, and checkout status automated deployment pipelines, letting you push updates confidently and roll back if anything goes awry by the end, you’ll have not only a production ready storefront but also the architectural know how to extend, scale, and secure any web application explore the finished e commerce application in action at web e commerce app let’s get started! key takeaways rapid backend setup launch and configure a full e‑commerce data model in minutes with back4app’s low‑code platform secure user flows implement robust sign‑up, login, and logout using cloud code and session tokens api first development access your data via auto generated rest/graphql endpoints and the parse sdk for any client business logic in cloud code centralize core operations—product crud, cart management, and checkout—while enforcing permissions containerized frontend deployment package and deploy your next js storefront in back4app web deployment for consistent, scalable hosting prerequisites and environment setup to follow this tutorial, make sure you have the following a back4app account you can sign up for free on the back4app website https //www back4app com/signup node js installed, allowing you to manage dependencies with npm or yarn familiarity with javascript for writing custom cloud code and leveraging back4app’s sdk basic understanding of e commerce concepts like user authentication, product catalog management, and order processing git for version control, so you can track changes, roll back if necessary, and collaborate seamlessly ensuring you have the items above will help you maximize back4app’s capabilities and implement key e commerce features without getting bogged down creating and configuring your back4app account to start setting up your e commerce backend on back4app, visit back4app https //www back4app com and click sign up enter your email address, choose a strong password, and provide any required details once you verify your email, you’ll gain access to the back4app dashboard back4app sign up page inside the dashboard, select create new app or build new app and give your project a name—something descriptive so you can easily locate it later confirm your choices, then wait for the app creation process to finish the project dashboard will display classes, analytics, and configurations creating a back4app app with these steps, you’ve created an e commerce platform in the next section, you’ll design your data schema and prepare for product management, order handling, and user authentication designing your e commerce data schema to implement a scalable and maintainable backend for your e commerce platform, you’ll organize your data around seven core tables user , buyer , seller , product , cart , order , and orderdetails each table plays a focused role in supporting the overall functionality of the system, and together they form a normalized and efficient schema begin with the user table, which serves as the foundation for all user identities every person on your platform—regardless of their role—will authenticate using this table include fields such as username , password , and email to handle basic login add emailverified to track verification status, and authdata if you plan to support third party logins or oauth flows to distinguish between buyers and sellers, define a usertype field this field enables you to control access, manage views, and separate functionality based on user roles while still maintaining a single, consistent login system instead of mixing all user types in one table, create separate buyer and seller tables that reference user via the userid field this lets you store role specific data without bloating the core user table the buyer table can hold purchasing related fields like paymentinfo and shippingaddress , which are essential for checkout and delivery processes in contrast, the seller table tracks attributes relevant to merchants, such as storename , bio , and phonenumber with this separation, you can easily manage and query buyers and sellers independently, while still linking them back to their shared identity in user your product table is where items for sale are stored each product should include basic descriptive information such as a name, a detailed description, and one or more images for pricing and inventory management, you’ll also want to include fields for price, availability status via a boolean isactive , and stock quantity under quantityavailable crucially, each product must be linked to the seller who listed it to establish that relationship, add a sellerid foreign key that references the seller table this structure ensures that every item in your catalog is tied to a verified merchant and makes seller specific filtering straightforward to handle pre purchase behavior, introduce a cart table each cart belongs to a user, so include a userid field that connects back to user store an array of cart items , each representing a product the user intends to buy, along with any metadata you need like quantity or selected options tracking the cart’s totalprice allows you to quickly display checkout summaries without recalculating values on every request this setup supports basic cart functionality and simplifies session persistence if you find the array structure limiting—particularly if you need to record more complex item level data—you can always refactor the items into a separate table later when a buyer places an order, you’ll record the transaction in the order table each order is tied to a buyerid , referencing the buyer table to ensure the purchaser is valid and authorized in addition to this link, store the orderdate , the current orderstatus , and the total monetary value under the total field this gives you a clear summary of the purchase and supports workflows like order tracking and fulfillment since each order may contain multiple products, you’ll need an orderdetails table to manage the individual line items this table connects each item back to its parent order through orderid , and to the purchased product using productid to accurately record the state of the purchase, include the quantity bought and the unitprice at the time of sale separating order details in this way allows you to build reports, generate invoices, and handle returns or adjustments with precision this schema, with its clean separation of concerns and relational integrity, forms a strong foundation for your e commerce system with the data model now aligned to your platform’s real world workflows, you’re ready to begin implementing it in your backend start by setting up the user , buyer , and seller tables, and build outward from there setting up classes in the dashboard follow the steps below to create and link your entities in back4app you’ll define classes for user , buyer , seller , cart , product , order , and orderdetails , then establish pointers to represent relationships like inheritance, one to many, and many to many access the database browser open your application's dashboard and create a new class named user click on database from the left hand menu back4app dashboard creating the “user” class back4app automatically creates a user class the user class comes with the following columns username password email etc to add the usertype column, select add a new column add new column provide the column's name, type of data, default value, etc add usertype column note in parse, every class includes a default objectid field, which functions as the primary key this means objectid will effectively serve as userid in your relational model creating the “buyer” class to create the buyer class, return to the database browser and select add class create new class choose custom and name it buyer add buyer class add a pointer column called user , pointing to the user class create userid class this simulates the “inheritance” by referencing the base user’s objectid 3\ add the following columns shippingaddress (string) paymentinfo (string) when you create a new buyer object, you’ll link it to an existing user record by setting buyer user to that user’s objectid creating the “seller” class repeat the same process to create a seller class add a pointer column named user referencing the user class add these additional columns storename (string) bio (string) phonenumber (number) creating the “product” class select create a class again, naming it product add a pointer column called seller pointing to the seller class (this enforces a one to many relationship where one seller can have many products) add the following columns name (string) description (string) price (number) quantityavailable (number) isactive (boolean) images (array) stores objects that represent product images creating the “cart” class click create a class , name the class cart add a pointer column called user pointing to the user class (this links each cart to a specific user) then add the following columns to represent the items in the cart items (array) stores objects that represent each cart item each item can be an object like { product pointer to product, quantity number } totalprice (number) creating the “order” class create a new class named order add a pointer column called buyer that points to the buyer class (indicating one buyer can have many orders) include these columns orderdate (date or string, depending on your preference) orderstatus (string) creating the “orderdetails” class finally, create a class named orderdetails add two pointer columns order → references order product → references product then, add the remaining columns quantity (number) unitprice (number) this setup allows a many to many relationship between order and product through orderdetails , since each order can include multiple products, and each product can appear in multiple orders visualizing the relationships here’s a simplified entity relationship diagram (erd) reflecting the classes and their pointers dbschema2 once these classes are in place, you can handle sign ups and logins through the user class, create specialized buyer or seller records for different user types, and store product or order information with clear foreign key references by structuring your database this way, you gain a clean, maintainable design for any e commerce application with your schema in place, you’re ready to set up authentication and authorization to restrict who can list products, place orders, or perform administrative tasks the next step will show you how to configure secure sign up and login flows that build on the roles and classes you’ve just defined implementing authentication with back4app secure authentication is central to any e commerce platform, helping you protect user accounts, payment details, and personal data back4app simplifies this with multiple methods—from classic username/password combos to social logins or token based flows—ensuring you can offer your shoppers a straightforward, safe experience to set up authentication in your e commerce application, you will make use of cloud code cloud code extends your backend capabilities by letting you write custom business logic without hosting your own servers this means you can validate orders, calculate fees, or trigger notifications on specific events—entirely within back4app’s infrastructure it’s an ideal way to handle sensitive transactions or data processes that need tight control and swift execution to enable cloud code on back4app, open your app’s dashboard and locate the cloud code section find cloud code when you click cloud code , you will see a main js where you can start implementing custom functions cloud code to implement the authentication flow in back4app, you will need to deploy some functions on your cloud code to sign up users, login users and log out users register a new user (buyer by default) to register a new user, use parse’s sign up method set standard fields like username , password , and email , and include a custom field to indicate role either buyer or seller by default, new users are assigned the role of buyer until they choose to change it to start, create an auth js file, in your cloud code's cloud directory and add the code block below parse cloud define('signupuser', async (request) => { const { name, password, confirmpassword, email, shippingaddress, paymentinfo } = request params; // validate password match if (password !== confirmpassword) { throw new error('passwords do not match'); } const user = new parse user(); user set('username', name); user set('password', password); user set('email', email); user set('usertype', "buyer"); try { // sign up the user const signedupuser = await user signup(); console log('user registered ', signedupuser id); // create a buyer record linked to the new user const buyer = parse object extend('buyer'); const buyer = new buyer(); buyer set('user', signedupuser); buyer set('shippingaddress', shippingaddress); buyer set('paymentinfo', paymentinfo); const savedbuyer = await buyer save(); console log('buyer created ', savedbuyer id); return { success true, message 'user registered and buyer created', userid signedupuser id, buyerid savedbuyer id }; } catch (error) { console error('sign up failed ', error); throw new error('sign up failed ' + error message); } }); this cloud function handles user registration for buyers it validates input, creates a new parse user, assigns a role ( buyer ), and stores buyer specific data in a separate buyer class log in users to authenticate users, call parse’s built in parse user login method and return the session token to the client add the following code to your auth js file to implement this logic in your cloud code backend parse cloud define("loginuser", async (request) => { const { email, password } = request params; try { const user = await parse user login(email, password); // example block users with disabled flag if (user get("isdisabled")) { throw new parse error(403, "account is disabled"); } return { sessiontoken user getsessiontoken(), userid user id, }; } catch (error) { throw new parse error(101, "invalid credentials"); } }); this function takes an email and password from the client, attempts to authenticate the user, and returns the session token if successful if the account is flagged as disabled, it blocks access and throws a clear error log out to implement the log out function for your backend, add the code block below to your auth js file parse cloud define('logoutuser', async (request) => { const sessiontoken = request headers\['x parse session token']; if (!sessiontoken) { throw new error('session token required'); } const sessionquery = new parse query(' session'); sessionquery equalto('sessiontoken', sessiontoken); const session = await sessionquery first({ usemasterkey true }); if (session) { await session destroy({ usemasterkey true }); } return { success true, message 'session invalidated' }; }); this securely ends the session on the backend, preventing further use of the token with these cloud code functions in place, you now have a secure authentication system that registers users with role based logic authenticates and authorizes access using session tokens links user accounts to buyer specific records supports clean login and logout flows leverages back4app’s built in session and email verification tools building the business logic for your ecommerce app to manage users, products, carts, and transactions in your e commerce platform, you'll define a series of cloud code functions in back4app these functions allow you to create, read, update, and delete (crud) resources like sellers, products, and orders while maintaining secure access control tied to user roles below is a set of cloud functions that demonstrates how to work with key entities seller , product , cart , order , and orderdetails each function handles a specific backend operation and ensures that permissions are enforced through user validation and role checks seller create a seller profile for a user who wants to offer products on the platform creating a seller this function updates the current user’s role to seller and creates a seller record with store information to implement this in your cloud code, first create a seller js file and add the code block below to it parse cloud define('createseller', async (request) => { const currentuser = request user; // get the current logged in user if (!currentuser) { throw new error('user is not logged in'); } try { // check and update the user type const usertype = currentuser get('usertype'); if (usertype === 'buyer') { currentuser set('usertype', 'seller'); await currentuser save(); } // create the seller object const { businessname, bio, phone } = request params; const seller = parse object extend('seller'); const seller = new seller(); seller set('user', currentuser); seller set('storename', businessname); seller set('bio', bio); seller set('phonenumber', number(phone)); const newseller = await seller save(); console log('seller created ', newseller id); return { success true, message 'seller account created', sellerid newseller id }; } catch (error) { console error('error creating seller ', error); throw new error('error creating seller ' + error message); } }); this ensures that only authenticated users can become sellers, and it links the seller record to the corresponding user via a pointer product products are listed by sellers and can be browsed, queried, and purchased by buyers these functions let sellers create, retrieve, update, and delete their products, and also provide product access to buyers creating a product this function adds a new product for a logged in seller and attaches up to three product images to implement in your cloud code create a product js file and add the code block below to it parse cloud define("addproduct", async (request) => { // destructure parameters sent from the client const { name, description, price, quantityavailable, isactive, imagefiles } = request params; // optional check if user is logged in (request user is available when an active session exists) const currentuser = request user; if (!currentuser) { throw new error("unauthorized you must be logged in to add a product "); } // ensure the user is indeed a seller by checking their usertype const usertype = currentuser get("usertype"); if (usertype != "seller") { throw new error("this user is not a seller "); } const seller = parse object extend("seller"); const query = new parse query(seller); query equalto("userid", currentuser); // match the pointer field in seller const sellerobj = await query first({ usemasterkey true }); if (!sellerobj) { throw new error("no matching 'seller' object found for this user "); } if(!array isarray(imagefiles) || imagefiles length > 3) { throw new error("a maximum of 3 images are provided"); } // create the new product object const product = parse object extend("product"); const product = new product(); product set("seller", sellerobj); // pointer to the seller product set("name", name); product set("description", description); product set("price", number(price)); product set("quantityavailable", number(quantityavailable)); product set("isactive", isactive); product set("images", imagefiles); // save the product to the database try { const savedproduct = await product save(null, { usemasterkey true }); return savedproduct; } catch (error) { throw new error(`could not create product ${error message}`); } }); this function checks that the user is logged in and has a seller role, that a corresponding seller object exists, and that no more than three images are submitted once validated, it stores the product and links it to the seller querying all products this function retrieves all products in the system, which can be used for building a public storefront to implement this in your cloud code, add the code block below to your products js file parse cloud define("fetchallproducts", async (request) => { try { const product = parse object extend("product"); const query = new parse query(product); const products = await query find({ usemasterkey true }); // return products in a json friendly format return products map((product) => ({ id product id, sellerid product get("seller")? id, name product get("name"), description product get("description"), price product get("price"), quantityavailable product get("quantityavailable"), isactive product get("isactive"), createdat product createdat, updatedat product updatedat, })); } catch (error) { throw new error(`error fetching products ${error message}`); } }); this function fetches products with the usemasterkey flag, and formats them for frontend consumption querying a single product use this function when displaying detailed product info to buyers to implement this in your cloud code, add the code block below to your products js file parse cloud define("getsingleproduct", async (request) => { const { productid } = request params; const currentuser = request user; // ensure user is logged in if (!currentuser) { throw new error("you must be logged in to retrieve product information "); } if (!productid) { throw new error("missing required parameter productid "); } // query the product class const product = parse object extend("product"); const query = new parse query(product); query equalto("objectid", productid); try { const product = await query first({ usemasterkey true }); if (!product) { throw new error("product not found "); } // return a json friendly object return { objectid product id, name product get("name"), description product get("description"), price product get("price"), quantityavailable product get("quantityavailable"), isactive product get("isactive"), // optionally return more fields like images, category, etc }; } catch (error) { throw new error(`error fetching product ${error message}`); } }); this function returns full product details for one item it verifies that a valid productid is passed and ensures the requester is logged in querying seller’s products this function allows a seller to retrieve all of their own products to implement this in your cloud code, add the code block below to your products js file parse cloud define("getsellerproducts", async (request) => { const currentuser = request user; // ensure the user is logged in if (!currentuser) { throw new error("you must be logged in to fetch seller products "); } // if your schema depends on verifying the user is truly a seller, you can check usertype const usertype = currentuser get("usertype"); if (usertype !== "seller") { throw new error("only sellers can view their own products "); } // if you want to retrieve products for the currently logged in seller // fetch the seller record that points to currentuser const seller = parse object extend("seller"); const sellerquery = new parse query(seller); sellerquery equalto("user", currentuser); const sellerrecord = await sellerquery first({ usemasterkey true }); if (!sellerrecord) { throw new error("no matching seller record found for the current user "); } // finally, fetch all products pointing to this seller const product = parse object extend("product"); const productquery = new parse query(product); productquery equalto("seller", sellerrecord); productquery limit(1000); // adjust or paginate as needed try { const products = await productquery find({ usemasterkey true }); // return a more friendly json structure return products map((prod) => ({ objectid prod id, name prod get("name"), description prod get("description"), price prod get("price"), quantityavailable prod get("quantityavailable"), isactive prod get("isactive"), createdat prod createdat, updatedat prod updatedat, })); } catch (error) { throw new error(`error fetching seller products ${error message}`); } }); this function confirms the user is a seller, locates the associated seller record, and queries the product class using a pointer to the seller sellers use this to fetch all their own products deleting a product this function ensures only the seller who created a product can delete it to implement this in your cloud code, add the code block below to your products js file parse cloud define("deleteproduct", async (request) => { const { productid } = request params; const currentuser = request user; if (!currentuser) { throw new error("you must be logged in to delete a product "); } const usertype = currentuser get("usertype"); if (usertype !== "seller") { throw new error("only sellers can delete products "); } if (!productid) { throw new error("missing required parameter productid "); } // 1 find the seller record for the current user const seller = parse object extend("seller"); const sellerquery = new parse query(seller); sellerquery equalto("user", currentuser); const sellerrecord = await sellerquery first({ usemasterkey true }); if (!sellerrecord) { throw new error("no matching seller record found for the current user "); } // 2 fetch the product with a query that ensures the user owns it const product = parse object extend("product"); const productquery = new parse query(product); productquery equalto("objectid", productid); productquery equalto("seller", sellerrecord); // must match the correct seller const product = await productquery first({ usemasterkey true }); if (!product) { throw new error("product not found or you do not have permission to delete it "); } // 3 destroy the product try { await product destroy({ usemasterkey true }); return { message "product deleted successfully ", productid }; } catch (error) { throw new error(`error deleting product ${error message}`); } }); this function confirms the user’s ownership and then removes the product from the database updating a product allow sellers to modify a product's details using this function to implement this in your cloud code, add the code block below to your products js file parse cloud define("updateproduct", async (request) => { const { productid, name, description, price, quantityavailable, isactive } = request params; const currentuser = request user; if (!currentuser) { throw new error("you must be logged in to update a product "); } const usertype = currentuser get("usertype"); if (usertype !== "seller") { throw new error("only sellers can update products "); } if (!productid) { throw new error("missing required parameter productid "); } // 1 find the seller record for the current user const seller = parse object extend("seller"); const sellerquery = new parse query(seller); sellerquery equalto("user", currentuser); const sellerrecord = await sellerquery first({ usemasterkey true }); if (!sellerrecord) { throw new error("no matching seller record found for the current user "); } // 2 fetch the product const product = parse object extend("product"); const query = new parse query(product); query equalto("objectid", productid); query equalto("seller", sellerrecord); // must match the seller to ensure ownership const product = await query first({ usemasterkey true }); if (!product) { throw new error("product not found or you do not have permission to modify it "); } // 3 update product fields if (name !== undefined) product set("name", name); if (description !== undefined) product set("description", description); if (price !== undefined) product set("price", price); if (quantityavailable !== undefined) product set("quantityavailable", quantityavailable); if (isactive !== undefined) product set("isactive", isactive); // 4 save changes try { const updatedproduct = await product save(null, { usemasterkey true }); return { objectid updatedproduct id, name updatedproduct get("name"), description updatedproduct get("description"), price updatedproduct get("price"), quantityavailable updatedproduct get("quantityavailable"), isactive updatedproduct get("isactive"), }; } catch (error) { throw new error(`error updating product ${error message}`); } }); it ensures the user is a seller, confirms product ownership, and updates only the fields that are provided in the request cart the cart functions enable buyers to manage items they intend to purchase these functions include adding to cart, updating quantities, viewing contents, and removing items adding to cart this function adds a product to the buyer’s cart or updates the quantity if it already exists to implement this, create a cart js file and add the code block below to it parse cloud define("addtocart", async (request) => { const { productid, quantity } = request params; // ensure there is a currently logged in user const currentuser = request user; if (!currentuser) { throw new error("you must be logged in to modify the cart "); } if (!productid || !quantity) { throw new error("missing required parameters productid and quantity "); } // 1 fetch or create the user's cart const cart = parse object extend("cart"); const cartquery = new parse query(cart); cartquery equalto("user", currentuser); let cart = await cartquery first({ usemasterkey true }); if (!cart) { cart = new cart(); cart set("user", currentuser); cart set("items", \[]); // initialize empty array cart set("totalprice", 0); // initialize price } // 2 fetch the product for price details (or any other attributes you need) const product = parse object extend("product"); const productquery = new parse query(product); productquery equalto("objectid", productid); const product = await productquery first({ usemasterkey true }); if (!product) { throw new error("product not found "); } const productprice = product get("price") || 0; // 3 insert or update the item in the cart const cartitems = cart get("items") || \[]; // check if this product is already in the cart const existingitemindex = cartitems findindex( (item) => item product objectid === productid ); if (existingitemindex >= 0) { // if product is already in cart, update the quantity cartitems\[existingitemindex] quantity += quantity; } else { // otherwise, add a new entry cartitems push({ product { type "pointer", classname "product", objectid productid, }, quantity quantity }); } // 4 recalculate total price // e g , summation of productprice quantity for each cart item let total = 0; for (const item of cartitems) { if (item product objectid === productid) { // use productprice from the newly fetched product total += productprice item quantity; } else { // this is a simplified approach ideally, you'd also store a price attribute on each item // or re fetch each product's price // for demonstration, we'll just skip them } } cart set("items", cartitems); cart set("totalprice", total); // 5 save the cart object try { const savedcart = await cart save(null, { usemasterkey true }); return { message "cart updated successfully", cartid savedcart id, items savedcart get("items"), totalprice savedcart get("totalprice"), }; } catch (error) { throw new error(`error saving cart ${error message}`); } }); it ensures the user is authenticated, validates the product, updates the item list, and recalculates the total cart price querying the cart retrieve the contents of the current user's cart, including product details and subtotals to implement this, add the code block below to your cart js file parse cloud define("getcart", async (request) => { if (!request user) throw "user must be logged in "; const user = request user; const cart = parse object extend("cart"); const cartquery = new parse query(cart); cartquery equalto("user", user); cartquery include("items product"); // deep include const cart = await cartquery first(); if (!cart) return { items \[], totalprice 0 }; const items = cart get("items") || \[]; const parseditems = \[]; for (const item of items) { const product = item product; parseditems push({ productid product id, name product get("name"), price product get("price"), image product get("image")? url() || null, quantity item quantity, subtotal product get("price") item quantity, }); } return { cartid cart id, items parseditems, totalprice cart get("totalprice") || 0, }; }); this function uses include("items product") to fetch nested product data in one query editing the cart update the quantity of an item in the cart or remove it entirely if the new quantity is zero to implement this, add the code block below to your cart js file parse cloud define("updatecart", async (request) => { const { productid, newquantity } = request params; const currentuser = request user; if (!currentuser) { throw new error("you must be logged in to update the cart "); } if (!productid || newquantity === undefined) { throw new error("missing required parameters productid and newquantity "); } // fetch or create the user's cart const cart = parse object extend("cart"); const cartquery = new parse query(cart); cartquery equalto("user", currentuser); let cart = await cartquery first({ usemasterkey true }); if (!cart) { // if there's no existing cart, create one cart = new cart(); cart set("user", currentuser); cart set("items", \[]); cart set("totalprice", 0); } let cartitems = cart get("items") || \[]; // find the item matching the productid const itemindex = cartitems findindex( (item) => item product id === productid ); if (itemindex === 1) { throw new error("product not found in cart please add it first "); } // if newquantity <= 0, remove the item from the cart if (newquantity <= 0) { cartitems splice(itemindex, 1); } else { // otherwise, update the quantity cartitems\[itemindex] quantity = newquantity; } // recalculate total by fetching current prices from each product let total = 0; if (cartitems length > 0) { const product = parse object extend("product"); // for each item in the cart, fetch the product to get its price for (const item of cartitems) { const productquery = new parse query(product); productquery equalto("objectid", item product objectid); const product = await productquery first({ usemasterkey true }); if (product) { const productprice = product get("price") || 0; total += productprice item quantity; } } } // update and save the cart cart set("items", cartitems); cart set("totalprice", total); try { const updatedcart = await cart save(null, { usemasterkey true }); return { message "cart updated successfully", cartid updatedcart id, items updatedcart get("items"), totalprice updatedcart get("totalprice"), }; } catch (error) { throw new error(`error updating cart ${error message}`); } }); it revalidates all product prices during the update to ensure total accuracy deleting from the cart this function removes a product from the user’s cart to implement this, add the code block below to your cart js file parse cloud define("removefromcart", async (request) => { const { productid } = request params; const currentuser = request user; if (!currentuser) { throw new error("you must be logged in to remove items from the cart "); } if (!productid) { throw new error("missing required parameter productid "); } // fetch the user's cart const cart = parse object extend("cart"); const cartquery = new parse query(cart); cartquery equalto("user", currentuser); const cart = await cartquery first({ usemasterkey true }); if (!cart) { throw new error("no existing cart found for this user "); } let cartitems = cart get("items") || \[]; // filter out the item with the specified productid const filtereditems = cartitems filter( (item) => item product id !== productid ); // if nothing changed, the product wasn't in the cart if (filtereditems length === cartitems length) { throw new error("product not found in cart "); } // recalculate the cart total let total = 0; if (filtereditems length > 0) { const product = parse object extend("product"); for (const item of filtereditems) { const productquery = new parse query(product); productquery equalto("objectid", item product objectid); const product = await productquery first({ usemasterkey true }); if (product) { const productprice = product get("price") || 0; total += productprice item quantity; } } } // update and save the cart cart set("items", filtereditems); cart set("totalprice", total); try { const updatedcart = await cart save(null, { usemasterkey true }); return { message "item removed from cart", cartid updatedcart id, items updatedcart get("items"), totalprice updatedcart get("totalprice"), }; } catch (error) { throw new error(`error removing item from cart ${error message}`); } }); it filters the item from the cart array and recalculates the total before saving order these functions manage the ordering process—from creating orders to fetching a seller’s order history creating an order this function converts the buyer’s cart into an official order to implement this, create an order js file and add the code block below to it parse cloud define("createorder", async (request) => { const currentuser = request user; if (!currentuser) { throw new error("you must be logged in to place an order "); } // ensure the user is a buyer (assumes buyer class with user pointer) const buyer = parse object extend("buyer"); const buyerquery = new parse query(buyer); buyerquery equalto("user", currentuser); const buyer = await buyerquery first({ usemasterkey true }); if (!buyer) { throw new error("only buyers can place orders "); } // retrieve the cart for the user const cart = parse object extend("cart"); const cartquery = new parse query(cart); cartquery equalto("user", buyer get("user")); // assuming the user pointer is stored in buyer const cart = await cartquery first({ usemasterkey true }); if (!cart || !cart get("items") || cart get("items") length === 0) { throw new error("cart is empty"); } const items = cart get("items"); let totalamount = 0; // adjust stock and calculate total order price const orderdetails = \[]; for (const item of items) { const productid = item product id; const quantity = item quantity; const product = parse object extend("product"); const productquery = new parse query(product); productquery equalto("objectid", productid); const product = await productquery first({ usemasterkey true }); if (!product) { throw new error(`product with id ${productid} not found`); } const availablequantity = product get("quantityavailable"); if (availablequantity < quantity) { throw new error(`not enough stock for product ${product get("name")}`); } // reduce the product quantity product set("quantityavailable", availablequantity quantity); await product save(null, { usemasterkey true }); const unitprice = product get("price"); totalamount += unitprice quantity; // prepare order detail entry orderdetails push({ product, quantity, unitprice }); } // create the new order object const order = parse object extend("order"); const order = new order(); order set("buyer", buyer); // set the buyer pointer order set("total", totalamount); // set the total amount order set("orderstatus", "pending"); // set the order status order set("orderdate", new date()); // set the order date // save the order to the database try { const savedorder = await order save(null, { usemasterkey true }); // create orderdetails for each item const orderdetails = parse object extend("orderdetails"); for (const detail of orderdetails) { const orderdetail = new orderdetails(); orderdetail set("order", savedorder); orderdetail set("product", detail product); orderdetail set("quantity", detail quantity); orderdetail set("unitprice", detail unitprice); await orderdetail save(null, { usemasterkey true }); } // optionally, clear the cart after saving the order cart set("items", \[]); await cart save(null, { usemasterkey true }); return savedorder; } catch (error) { throw new error(`could not create order ${error message}`); } }); it validates the buyer, checks stock availability, reduces product inventory, saves both order and orderdetails , and clears the cart after a successful order getting seller orders this function retrieves all orders that include products sold by the current seller to implement this, add the code block below to your order js file parse cloud define("getsellerorders", async (request) => { const currentuser = request user; if (!currentuser) { throw new error("you must be logged in to view your orders "); } if (currentuser get("usertype") !== "seller") { throw new error("only sellers can access this endpoint "); } try { const seller = parse object extend("seller"); const seller = await new parse query(seller) equalto("userid", currentuser) first({ usemasterkey true }); if (!seller) { throw new error("seller profile not found "); } // find products by this seller const product = parse object extend("product"); const productquery = new parse query(product); productquery equalto("seller", seller); const products = await productquery find({ usemasterkey true }); if (!products || products length === 0) { return \[]; } // get product ids const productids = products map(product => product id); // find order details containing these products const orderdetails = parse object extend("orderdetails"); const orderdetailsquery = new parse query(orderdetails); orderdetailsquery containedin("product", products); const orderdetails = await orderdetailsquery find({ usemasterkey true }); if (!orderdetails || orderdetails length === 0) { return \[]; } const orderids = \[ new set(orderdetails map(detail => detail get("order") id))]; // query orders for these ids const order = parse object extend("order"); const orderquery = new parse query(order); orderquery containedin("objectid", orderids); orderquery include("buyer"); const orders = await orderquery find({ usemasterkey true }); // return the orders return orders map(order => ({ id order id, total order get("total"), status order get("orderstatus"), date order get("orderdate"), buyer order get("buyer") })); } catch (error) { throw new error(`could not fetch orders ${error message}`); } }); it locates products owned by the seller, queries orderdetails for those products, fetches the corresponding orders, and returns a simplified structure including buyer info updating order status this function toggles the status of an order between “pending” and “completed ” to implement this, add the code block below to your order js file parse cloud define("updateorder", async (request) => { const { orderid } = request params; const currentuser = request user; if (!currentuser) { throw new error("you must be logged in to view your orders "); } if (currentuser get("usertype") !== "seller") { throw new error("only sellers can access this endpoint "); } // validate the input parameter if (!orderid) { throw new error("missing required field orderid"); } try { // find the order with the specified orderid const order = parse object extend("order"); const query = new parse query(order); query equalto("objectid", orderid); const order = await query first({ usemasterkey true }); if (!order) { throw new error("order not found"); } // check current status // update the order status if (order get("orderstatus") === "completed") { order set("orderstatus", "pending"); } else { order set("orderstatus", "completed"); } // save the updated order await order save(null, { usemasterkey true }); return { success true, message "order status updated to completed" }; } catch (error) { throw new error(`could not update order status ${error message}`); } }); it ensures only sellers can perform this action and that the order exists before updating the status these backend functions give your e commerce app the ability to securely manage all core operations—product listings, buyer carts, orders, and seller inventory—directly within back4app using cloud code to ensure you can access these cloud functions externally, you need to register all your cloud code files in your main js file, you can do that by adding the code block below to your main js file //main js require(" /auth js") require(" /cart js") require(" /order js") require(" /product js") require(" /seller js") frontend creation to build your e commerce storefront visually, you will use v0 dev to do this, begin by visiting v0 dev http //v0 dev create an account if you don't have one already once your account is set up you can start creating your frontend to create your frontend, enter the prompt below create an e commerce web application with authentication features and a buyer and seller feature the prompt will build a next js ecommerce app with the features requested create ecommerce app using the preview feature, you can navigate through the application to confirm everything works as expected if there are some complications or you want to add more features you can pass another prompt and v0 will modify the application for example, pass the prompt the seller can create, add, delete and update products this prompt will modify the app, creating pages where the seller can perform crud operations modify ecommerce app finally, pass the prompt do not sort products by categories and remove the categories page and input fields, remove the second and third step from the process of becoming a seller and add a bio input field to the first step, users should only sign in with email, and enhance the seller functionality to fully support product management (crud operations) this prompt will make the final edits to the application to get a preview of the modified application, click on the view button in the highlighted section in the image above once you are sure the application is what you want, the next step is getting the project to your local device to do this, click on the download button that v0 generates with the prompt response download button clicking on the button will reveal a dropdown menu with a link and a download zip button dropdown menu next, click the download zip button once you are done downloading the zip, open your terminal and create a new folder called ecommerce app in your preferred directory mkdir ecommerce app now extract the contents of the zip folder into the ecommerce app folder navigate to the ecommerce app directory on your terminal and install the necessary dependencies to do this, run the following command cd ecommerce app npm install after installing the dependencies, run the npm run dev command on your terminal to view the project on your localhost server integrating your frontend with your backend to connect your frontend with the cloud code functions in your back4app backend, you'll use the parse javascript sdk the sdk enables you to authenticate users, call backend functions, and interact with your app’s data models securely and efficiently to set up the sdk, run the following command in your project's directory in your terminal npm install parse then create a lib/parse js file to configure the connection in this file, input the code block below import parse from "parse/dist/parse min js"; parse initialize("your app id", "your javascript key"); parse serverurl = "https //parseapi back4app com"; export default parse; replace your app id and your javascript key with the credentials found in your back4app dashboard under app settings this basic configuration ensures the sdk knows how to connect to your specific project now that you have connected your frontend to your backend, you can begin writing functions to call the cloud code functions you defined in your back4app application authentication on the client this section shows how to handle user sign up, login, and logout in your frontend using the parse sdk each function corresponds to a cloud code function or sdk method you've implemented in your back4app backend in your application, the app/auth/register directory holds the logic for signing up users in the page tsx define the formdata state this state will hold the credentials necessary for signing up a user the formdata state should look like this const \[formdata, setformdata] = usestate({ name "", email "", password "", confirmpassword "", shippingaddress "", paymentinfo "", }); with the credentials passed into the formdata , you can call the signupuser cloud function you defined in your back4app application ensure to import parse from the lib/parse js import parse from "@/lib/parse"; const handlesubmit = async(e react formevent) => { e preventdefault(); try { const response = await parse cloud run("signupuser", { name formdata name, email formdata email, password formdata password, confirmpassword formdata confirmpassword, shippingaddress formdata shippingaddress, paymentinfo formdata paymentinfo, }); console log("signup successful ", response); } catch (error any) { console error("signup failed ", error); } } this function will run when you submit the sign up form it calls the signupuser cloud function defined in cloud code the function passes user credentials and buyer specific data (like shipping and payment info) finally, it logs the response if the operation is successful or prints an error if it fails signing in users to log in a user, use the loginuser cloud code function in your backend navigate to the app/auth/login directory in your application within the page tsx file, v0 will have created the state containing the user's credentials you need to log the user in all you need to do is pass those credentials to the loginuser function for example import parse from "@/lib/parse"; const handlesubmit = async (e react formevent) => { e preventdefault(); setisloading(true); try { const result = await parse cloud run("loginuser", { email, password }); // log in using returned session token await parse user become(result sessiontoken); console log("user logged in with session ", result sessiontoken); setisloading(false); router push("/"); // proceed to app } catch (error) { console error("login failed ", error); } }; this function invokes the cloud function loginuser , sending the user’s login credentials to the server after receiving a valid session token in response, it uses parse user become to authenticate the client and establish the session as belonging to the logged in user logging out users to securely log out a user, you’ll call both parse user logout() and your custom logoutuser cloud code function this ensures the session token is cleared both on the client and invalidated on the server you will find the logout button in your header component this component will be in your components folder in the root directory in the component, define this function const handlelogout = async () => { const sessiontoken = parse user current()? get("sessiontoken"); if (sessiontoken) { await parse user become(sessiontoken); // ensures proper context await parse cloud run("logoutuser"); // delete the session on server } await parse user logout(); // clear the local session }; this function will log out a user and clear the session both on the client and server in the jsx part of the component, bind the function to the log out button using the onclick event for example \<dropdownmenuitem onclick={handlelogout}> logout \</dropdownmenuitem> seller onboarding this section shows a function to let buyers upgrade their account and register as sellers in your application, navigate to the app/seller/register directory in this directory, you will find your page tsx file where you will define the function that calls the createseller cloud function this function is responsible for creating a seller profile for the current user in the page tsx file, modify the formdata state to look like this const \[formdata, setformdata] = usestate({ phone "", bio "", businessname "", }); replace the logic in the handlesubmit function created by v0 with the logic below const handlesubmit = async (e react formevent) => { e preventdefault(); try { const result = await parse cloud run("createseller", { businessname formdata businessname, bio formdata bio, phone formdata phone, }); console log("seller created ", result sellerid); } catch (error) { console error("error creating seller ", error); } }; call this function when submitting the form to create a seller profile for your users product management use these function calls in your frontend to manage product operations as a seller creating a product to call the cloud code function that adds a product to the database, locate the app/seller/products/new directory within this directory is your page tsx file, in this file is a form this form takes the information for the product including images modify the product state to look like this const \[product, setproduct] = usestate({ name "", price "", description "", stock "", status "active", }); also create a state to hold your images const \[images, setimages] = usestate\<file\[]>(\[]); now, write a function to handle adding the images to the database this function should look like this const handleimageupload = async (event) => { event preventdefault(); try { let name = "image jpg"; const file = new parse file(name, event target files\[0]); const photo = await file save(); setimages((prev) => \[ prev, photo]); console log("file saved ", file); alert(`image uploaded successfully`); } catch (error) { console error("error saving file ", error); } }; bind this function to the input responsible for file upload using the onchange event next, define the handlesubmit function this function calls the addproduct cloud code while passing the necessary information like so const handlesubmit = async (e react formevent) => { e preventdefault(); try { interface addproductparams { name string; description string; price number; quantityavailable number; isactive boolean; } interface addproductresponse { id string; } parse cloud run\<addproductresponse, addproductparams>("addproduct", { name product name, description product description, price product price, quantityavailable product stock, isactive product status === "active", imagefiles images, }) then((response) => { console log("product created ", response id); }); } catch (error) { console error("error creating product ", error); } }; this call submits product data—including images—to the backend to create a new listing fetch all products this call retrieves the entire catalog for public product listings or a home page feed to create the function that calls the fetchallproducts cloud function, navigate to the app/products directory in the page tsx file, add this code interface product { id string; name string; description string; price number; image? string; } const \[products, setproducts] = usestate\<product\[]>(\[]); async function getallproducts() { try { const response = await parse cloud run("fetchallproducts"); console log("products fetched ", response); return response; } catch (error) { console error("error fetching products ", error); throw error; } } this code block above defines an interface for the products and a products state the getallproducts function calls the cloud function fetchallproducts to get all products on the database note that you need to call the getallproducts function above inside a useeffect() hook to fetch and render products on page load like so useeffect(() => { getallproducts() then((products) => { setproducts(products); }) catch((error) => { console error("error fetching products ", error); }); }, \[]); get a single product this call retrieves full details about a specific product navigate to the \[id] folder in your app/products directory this folder holds the page tsx file that will contain the logic for fetching a single product's details in the page tsx file, write this code interface product { id string; name string; description string; price number; images? string\[]; quantityavailable number; } const \[product, setproduct] = usestate\<product>({ id "", name "", description "", price 0, images \[], quantityavailable 0, }); async function getsingleproduct() { try { const response = await parse cloud run("getsingleproduct", {productid params id}); console log("product fetched ", response); return response; } catch (error) { console error("error fetching products ", error); throw error; } } useeffect(() => { getsingleproduct() then((product) => { setproduct(product); }) catch((error) => { console error("error fetching products ", error); }); }, \[]); this code block defines the interface for the product object, sets up a state variable product with default values the getsingleproduct function calls your getsingleproduct cloud code function using a productid from the route params this useeffect hook runs once when the component mounts update a product when a seller edits a product, call this function with the updated fields to update products, you need a form with input fields collecting the new data, you can find this form in the page tsx file located in the app/seller/products/\[id]/edit directory before updating a product, you need to fetch the product and to do this add this code to your page tsx file const \[product, setproduct] = usestate({ id "", name "", price "", description "", stock "", images \["", "", ""], status "active", }); useeffect(() => { async function fetchproduct() { try { const response = await parse cloud run("getsingleproduct", { productid params id, }); setproduct({ id response objectid, name response name || "", price string(response price ?? "0"), description response description || "", stock string(response quantityavailable ?? "0"), // fallback to placeholders if actual image data is not provided images \[ response image1 || `/placeholder svg?height=500\&width=500\&text=product`, response image2 || `/placeholder svg?height=500\&width=500\&text=productview+2`, response image3 || `/placeholder svg?height=500\&width=500\&text=productview+3`, ], status response isactive ? "active" "out of stock", }); } catch (error) { console error("error fetching product ", error); } } fetchproduct(); }, \[]); this code fetches the details of a single product from your back4app backend with the getsingleproduct cloud code function and stores the details in the component state product to display as the default value in your form beforee you modify it after fetching the product details, you can change the details using the form after filling the form, submitting the form will call a handlesubmit function which will hold the logic for updating your product your handlesubmit function should look like this const handlesubmit = async (e react formevent) => { e preventdefault(); try { await parse cloud run("updateproduct", { productid product id, name product name, description product description, price parsefloat(product price), quantityavailable parseint(product stock, 10), isactive product status === "active", }); } catch (error) { console error("error updating product ", error); } }; this function calls your updateproduct cloud code function and sends an object with the updated product data delete a product use this function to delete a product after confirmation from the seller to delete a product, you need to add a handledelete function that holds the logic necessary for deleting the product you will define the handledelete function in the page tsx file in the app/seller/products/\[id]/edit directory const handledelete = async () => { const confirmdelete = confirm( "are you sure you want to delete this product? this action cannot be undone " ); if (!confirmdelete) return; try { await parse cloud run("deleteproduct", { productid product id, }); } catch (error) { console error("error deleting product ", error); } }; the handledelete function first confirms the user’s intent before calling the deleteproduct cloud code function defined in your backend bind the handledelete function to the delete button in the jsx part of the component for example \<button type="button" variant="destructive" onclick={handledelete} \> \<trash2 classname="h 4 w 4 mr 2" /> delete product \</button> get seller’s products use this to fetch all products owned by the currently logged in seller you will define the function to handle fetching the seller's products in the page tsx file in the app/seller/dashboard directory in the file, write this code const \[products, setproducts] = usestate< { objectid string; name string; price number; quantityavailable number; sales number; isactive boolean; }\[] \>(\[]); useeffect(() => { async function fetchproducts() { try { const result = await parse cloud run("getsellerproducts"); setproducts(result); } catch (error) { console error("error fetching products ", error); } }; fetchproducts(); }, \[]); this code block defines the products state and uses the useeffect hook to call the fetchproducts function once on load the fetchproducts function calls the getsellerproducts cloud code function and updates the products state with the call result cart management these calls allow buyers to manage their shopping cart before placing an order add to cart this call adds a selected product to the user’s cart or increments its quantity locate the page tsx file in the app/products directory and add these following lines of code async function handleaddtocart(productid string, quantity number = 1) { try { const response = await parse cloud run("addtocart", { productid, quantity, }); console log("add to cart success ", response); } catch (error) { console error("failed to add to cart ", error); } } the function handleaddtocart accepts productid and optional quantity as arguments and it calls the addtocart cloud code on your backend this function should run when your users click on the "add to cart" button in your product card for example \<button classname="w full" size="sm" onclick={() => handleaddtocart(product id)}> \<shoppingcart classname="h 4 w 4 mr 2" /> add to cart \</button> view cart use this to fetch the cart’s contents and render a live cart summary to do this, navigate to the page tsx file in the app/cart directory within this file, add the code block below interface cartitem { id string; // product's objectid name string; price number; quantity number; image string; } const \[cartitems, setcartitems] = usestate\<cartitem\[]>(\[]); useeffect(() => { async function fetchcart() { try { const response = await parse cloud run("getcart"); const parsed = response items map((item) => ({ id item productid, name item name, price item price, quantity item quantity, image item image, })); setcartitems(parsed); } catch (error) { console error("failed to fetch cart ", error); } } fetchcart(); }, \[]); the code block above defines the shape of the cart data in frontend with the interface cartitem , defines the cartitems state that holds the cart items it also uses useeffect to trigger the fetchcart function once on page load the fetchcart function calls the cloud code function getcart and retrieves cart from your backend it uses the map method to convert the backend format to frontend format before saving the processed cart data to the cartitems state update cart item this call changes the quantity of a specific product in the cart within the page tsx file in the app/cart directory, you will find an updatequantity function replace that function with the one below const updatequantity = async (productid string, newquantity number) => { if (newquantity < 1) return; try { await parse cloud run("updatecart", { productid, newquantity, }); console log("updated the cart"); } catch (error) { console error("failed to update cart item ", error); } }; this function takes two parameters, productid and the updated quantity the user wants to set newquantity it calls your updatecart cloud function and sends both the productid and the newquantity as parameters you bind this function to the +/ buttons using the onclick event like so \<div classname="flex items center gap 2"> \<button variant="outline" size="icon" classname="h 8 w 8" onclick={() => updatequantity(item id, item quantity 1)} \> \<minus classname="h 3 w 3" /> \<span classname="sr only">decrease quantity\</span> \</button> \<span classname="w 8 text center">{item quantity}\</span> \<button variant="outline" size="icon" classname="h 8 w 8" onclick={() => updatequantity(item id, item quantity + 1)} \> \<plus classname="h 3 w 3" /> \<span classname="sr only">increase quantity\</span> \</button> \</div> remove from cart removes an item entirely from the cart to do this, add the code block below to the page tsx file in the app/cart directory within this file const removeitem = async (productid string) => { try { await parse cloud run("removefromcart", { productid, }); setcartitems((items) => items filter((item) => item id !== productid)); } catch (error) { console error("failed to remove item ", error); } }; this function, removeitem , removes a specific product from the user's cart by calling the cloud function removefromcart on the backend the function also updates the local cart state in the frontend to reflect the change bind this function to the "remove item" button, like so \<button variant="ghost" size="icon" classname="h 8 w 8 text muted foreground" onclick={() => removeitem(item id)} \> \<trash2 classname="h 4 w 4" /> \<span classname="sr only">remove item\</span> \</button> order management these functions handle the creation and tracking of orders for buyers and sellers create an order this creates an order from the current contents of the user’s cart you also define this function in the page tsx file in the app/cart directory the function holding the logic for creating the order should look like this const handleorder = async () => { try { const user = parse user current(); if (!user) { throw new error("you must be logged in to place an order "); } const result = await parse cloud run("createorder"); console log("order created successfully ", result); } catch (error any) { console error("failed to create order ", error); } }; this function, handleorder , handles the checkout process by placing an order through your back4app backend it checks if a user is logged in, then calls the createorder cloud function to convert the current user's cart into an official order to call this at checkout, bind the function to the "checkout" button using the onclick event for example \<button classname="w full" onclick={handleorder}>proceed to checkout\</button> view seller orders sellers can use this call to view orders that include their products define this function in the page tsx file in the app/seller/dashboard directory add the following lines of code to the page tsx file const \[ordersdata, setordersdata] = usestate<{ id string; total number; buyer string; date date; status string; }\[] \>(\[]); async function fetchsellerorders() { try { const orders = await parse cloud run("getsellerorders"); console log("seller orders ", orders); setordersdata(orders); } catch (err) { console error("error fetching seller orders ", err); } }; this code retrieves a list of orders that include the seller's products and stores them in the local state ordersdata for display in a seller dashboard or order management view ensure to call the function in a useeffect hook so that the function runs once on page load update an order this toggles an order’s status between "pending" and "completed" define this function in the page tsx file in the app/seller/dashboard directory the function should look like this const handleupdate = async (id string) => { const confirmupdate = confirm( "are you sure you want to update this order?" ); if (!confirmupdate) return; try { await parse cloud run("completeorder", { orderid id, }); console log("updated order"); } catch (error) { console error("error updating order ", error); } }; this function, handleupdate , updates the status of an existing order by calling the cloud function named completeorder on your back4app backend bind this function to an "edit" button in the jsx part of the component like so \<button variant="ghost" size="icon" onclick={() => {handleupdate(order id)}}> \<pencil classname="h 4 w 4" /> \<span classname="sr only">view\</span> \</button> deploying the frontend on back4app containers back4app containers offer a streamlined way to package and deploy your frontend application instead of juggling separate hosting services, you can store all dependencies within a docker image, ensuring consistent performance and simplifying maintenance this container based approach is especially useful for next js applications, where you can optimize builds for speed and reliability to containerize your application, create a dockerfile to define how your app is built and served below is a sample dockerfile for a next js application \# stage 1 build the next js app from node 20 alpine as builder workdir /app copy package json package lock json / run npm install copy run npm run build \# stage 2 run the next js app from node 20 alpine workdir /app copy from=builder /app / expose 3000 cmd \["npm", "start"] after creating your dockerfile, create a dockerignore file and add these commands \# node modules (reinstalled in docker) node modules \# next js build output next out \# logs npm debug log yarn debug log yarn error log pnpm debug log \# env files (optional — only if you handle secrets another way) env env local env development env production env test \# os / ide / editor junk ds store thumbs db vscode idea \# git git gitignore now you can build build and test your application locally to do this, run thee following command in your terminal docker build t ecommerce app docker run p 3000 3000 ecommerce app open http //localhost 3000 to ensure your site runs properly once you've verified everything works as expected locally, it's time to push your code to github and deploy it through back4app make sure your code is committed and pushed to a github repository this will allow back4app to access your project for deployment in your back4app account, go to your dashboard and click on the dashboard dropdown menu at the top of the screen dashboard menu from the dropdown, select web deployment platform web deployment platform this will take you to the web application deployment page deploy web application page click the deploy a web app button to start the deployment process link github repo then, click on import github repo and choose the repository that contains your dockerfile assign a name to your project (e g , ecommerce back4app) follow the guided setup to build and deploy your app once deployment completes, back4app will display a confirmation page like this successful deployment the highlighted area in the image above is the url where your application is live you can use it to view and test your app directly in a web browser once deployed, use the back4app dashboard to monitor build logs, track container health, and roll back to previous versions if needed the dashboard displays real time updates on container status, making it easier to spot errors and maintain a stable environment for your users with containers, you gain a flexible, portable frontend solution that pairs seamlessly with your back4app backend, paving the way for consistent, hassle free releases you can visit the e commerce website built in this tutorial here https //ecommerceback4app mcphit37 b4a run/ conclusion congratulations—you’ve now assembled every layer of a battle tested, production ready e commerce stack back end setup from provisioning your back4app account to modelling users, products, and orders security & apis implementing robust authentication, and exposing your data via rest and graphql endpoints business logic & real time updates automating workflows with cloud code and streaming live changes through livequery front end deployment wiring in the javascript sdk and shipping a next js storefront in back4app containers what’s next? dive into the back4app documentation https //www back4app com/docs and the parse platform guide https //docs parseplatform org for in depth reference, or join the community forum to pick up advanced tips and sample apps from maintainers and fellow developers this foundation is just the beginning—stretch it further by integrating webhooks and scheduled jobs, wiring up payment gateways, or building a mobile companion app keep iterating, refactoring, and evolving your codebase—and watch your storefront grow alongside your ambitions