Quickstarters
How to Build an E-Commerce Backend?
92 min
en este tutorial práctico, crearás una aplicación de comercio electrónico de pila completa y sólida desde cero utilizando un backend como servicio a lo largo del camino, dominarás autenticación de usuarios segura, asegurando que solo los compradores y administradores autorizados tengan acceso modelos de datos intuitivos, diseñados para impulsar catálogos de productos, perfiles de clientes e historiales de pedidos apis restful y en tiempo real, para que tu frontend siempre esté sincronizado con el inventario, los carritos y el estado de pago canales de implementación automatizados, permitiéndote enviar actualizaciones con confianza y revertir si algo sale mal al final, no solo tendrás una tienda lista para producción, sino también el conocimiento arquitectónico para extender, escalar y asegurar cualquier aplicación web explora la aplicación de comercio electrónico terminada en acción en aplicación web de comercio electrónico ¡comencemos! conclusiones clave configuración rápida del backend lanza y configura un modelo de datos de comercio electrónico completo en minutos con la plataforma de bajo código de back4app flujos de usuario seguros implementa un registro, inicio de sesión y cierre de sesión robustos utilizando cloud code y tokens de sesión desarrollo primero api accede a tus datos a través de puntos finales rest/graphql auto generados y el sdk de parse para cualquier cliente lógica de negocios en cloud code centraliza las operaciones principales crud de productos, gestión de carritos y pago, mientras aplicas permisos despliegue de frontend contenerizado empaqueta y despliega tu tienda next js en el despliegue web de back4app para un alojamiento consistente y escalable requisitos previos y configuración del entorno para seguir este tutorial, asegúrate de tener lo siguiente una cuenta de back4app puedes registrarte gratis en el sitio web de back4app https //www back4app com/signup node js instalado, lo que te permite gestionar dependencias con npm o yarn familiaridad con javascript para escribir código en la nube personalizado y aprovechar el sdk de back4app comprensión básica de conceptos de comercio electrónico como autenticación de usuarios, gestión de catálogos de productos y procesamiento de pedidos git para control de versiones, para que puedas rastrear cambios, revertir si es necesario y colaborar sin problemas asegurarte de tener los elementos anteriores te ayudará a maximizar las capacidades de back4app e implementar características clave de comercio electrónico sin quedarte atascado creando y configurando tu cuenta de back4app para comenzar a configurar tu backend de comercio electrónico en back4app, visita back4app https //www back4app com y haz clic en registrarse ingresa tu dirección de correo electrónico, elige una contraseña fuerte y proporciona cualquier detalle requerido una vez que verifiques tu correo electrónico, tendrás acceso al panel de control de back4app página de registro de back4app dentro del panel de control, selecciona crear nueva aplicación o construir nueva aplicación y dale un nombre a tu proyecto—algo descriptivo para que puedas localizarlo fácilmente más tarde confirma tus elecciones, luego espera a que finalice el proceso de creación de la aplicación el panel del proyecto mostrará clases, análisis y configuraciones creando una aplicación back4app con estos pasos, has creado una plataforma de comercio electrónico en la siguiente sección, diseñarás tu esquema de datos y te prepararás para la gestión de productos, el manejo de pedidos y la autenticación de usuarios diseñando tu esquema de datos de comercio electrónico para implementar un backend escalable y mantenible para tu plataforma de comercio electrónico, organizarás tus datos en torno a siete tablas principales usuario , comprador , vendedor , producto , carrito , pedido , y detallesdelpedido cada tabla desempeña un papel específico en el apoyo a la funcionalidad general del sistema, y juntas forman un esquema normalizado y eficiente comience con la user tabla, que sirve como la base para todas las identidades de usuario cada persona en su plataforma—independientemente de su rol—se autentificará utilizando esta tabla incluya campos como username , password , y email para manejar el inicio de sesión básico agregue emailverified para rastrear el estado de verificación, y authdata si planea soportar inicios de sesión de terceros o flujos de oauth para distinguir entre compradores y vendedores, defina un campo usertype este campo le permite controlar el acceso, gestionar vistas y separar la funcionalidad según los roles de usuario, mientras mantiene un sistema de inicio de sesión único y consistente en lugar de mezclar todos los tipos de usuario en una tabla, cree tablas separadas de buyer y seller que hagan referencia a user a través del campo userid esto le permite almacenar datos específicos de rol sin aumentar el tamaño de la tabla de usuario principal la tabla buyer puede contener campos relacionados con la compra como paymentinfo y shippingaddress , que son esenciales para los procesos de pago y entrega en contraste, la tabla seller rastrea atributos relevantes para los comerciantes, como storename , bio , y phonenumber con esta separación, puede gestionar y consultar fácilmente a compradores y vendedores de manera independiente, mientras los vincula de nuevo a su identidad compartida en user tu producto tabla es donde se almacenan los artículos en venta cada producto debe incluir información descriptiva básica, como un nombre, una descripción detallada y una o más imágenes para la gestión de precios e inventario, también querrás incluir campos para el precio, el estado de disponibilidad a través de un booleano isactive , y la cantidad de stock bajo quantityavailable crucialmente, cada producto debe estar vinculado al vendedor que lo listó para establecer esa relación, agrega una sellerid clave externa que haga referencia a la seller tabla esta estructura asegura que cada artículo en tu catálogo esté vinculado a un comerciante verificado y hace que el filtrado específico por vendedor sea sencillo para manejar el comportamiento previo a la compra, introduce una cart tabla cada carrito pertenece a un usuario, así que incluye un userid campo que se conecte de nuevo a user almacena un array de items , cada uno representando un producto que el usuario pretende comprar, junto con cualquier metadato que necesites, como cantidad u opciones seleccionadas rastrear el totalprice del carrito te permite mostrar rápidamente resúmenes de pago sin recalcular valores en cada solicitud esta configuración soporta la funcionalidad básica del carrito y simplifica la persistencia de sesión si encuentras que la estructura de array es limitante—particularmente si necesitas registrar datos más complejos a nivel de artículo—siempre puedes refactorizar los artículos en una tabla separada más adelante cuando un comprador realiza un pedido, registrarás la transacción en la order tabla cada pedido está vinculado a un buyerid , haciendo referencia a la buyer tabla para asegurar que el comprador sea válido y esté autorizado además de este enlace, almacena la orderdate , el actual orderstatus , y el valor monetario total bajo el campo total esto te da un resumen claro de la compra y apoya flujos de trabajo como el seguimiento y cumplimiento de pedidos dado que cada pedido puede contener múltiples productos, necesitarás una orderdetails tabla para gestionar los artículos individuales esta tabla conecta cada artículo de nuevo a su pedido principal a través de orderid , y al producto comprado usando productid para registrar con precisión el estado de la compra, incluya la cantidad comprada y el preciounitario en el momento de la venta separar los detalles del pedido de esta manera le permite generar informes, crear facturas y manejar devoluciones o ajustes con precisión este esquema, con su clara separación de preocupaciones e integridad relacional, forma una base sólida para su sistema de comercio electrónico con el modelo de datos ahora alineado a los flujos de trabajo del mundo real de su plataforma, está listo para comenzar a implementarlo en su backend comience configurando las tablas usuario , comprador , y vendedor y construya a partir de ahí configurando clases en el panel de control siga los pasos a continuación para crear y vincular sus entidades en back4app definirá clases para usuario , comprador , vendedor , carrito , producto , pedido , y detallesdelpedido , luego establecerá punteros para representar relaciones como herencia, uno a muchos y muchos a muchos acceder al navegador de base de datos abra el panel de control de su aplicación y cree una nueva clase llamada usuario haga clic en base de datos en el menú de la izquierda back4app dashboard creando la clase “usuario” back4app crea automáticamente una clase usuario la usuario clase viene con las siguientes columnas nombredeusuario contraseña correoelectrónico etc para agregar la tipodeusuario columna, seleccione agregar una nueva columna add new column proporcione el nombre de la columna, tipo de dato, valor por defecto, etc add usertype column nota en parse, cada clase incluye un objectid por defecto, que funciona como la clave primaria esto significa que objectid servirá efectivamente como userid en su modelo relacional creando la clase “comprador” para crear la clase comprador, regrese al navegador de base de datos y seleccione agregar clase create new class elija personalizado y nómbralo comprador add buyer class agregue una columna de puntero llamada usuario , apuntando a la clase user create userid class esto simula la “herencia” al referenciar el objectid , del usuario base 3\ agregue las siguientes columnas direccióndeenvio (cadena) informacióndepago (cadena) cuando creas un nuevo objeto comprador, lo vincularás a un registro de usuario existente configurando buyer user al objectid de ese usuario creando la clase “vendedor” repite el mismo proceso para crear una vendedor clase agrega una columna puntero llamada usuario que haga referencia a la clase usuario agrega estas columnas adicionales nombredetienda (cadena) biografía (cadena) númerodeteléfono (número) creando la clase “producto” seleccionar crear una clase de nuevo, nombrándola producto agregar una columna de puntero llamada vendedor apuntando a la clase vendedor (esto impone una relación de uno a muchos donde un vendedor puede tener muchos productos) agregar las siguientes columnas nombre (cadena) descripción (cadena) precio (número) cantidaddisponible (número) esactivo (booleano) imágenes (array) almacena objetos que representan imágenes de productos creando la clase “carrito” haga clic en crear una clase , nombre de la clase carrito agregar una columna de puntero llamada usuario apuntando a la clase usuario (esto vincula cada carrito a un usuario específico) luego, agregue las siguientes columnas para representar los artículos en el carrito artículos (array) almacena objetos que representan cada artículo del carrito cada artículo puede ser un objeto como { producto puntero a producto, cantidad número } preciototal (número) creando la clase “orden” crea una nueva clase llamada order agrega una columna pointer llamada buyer que apunta a la clase buyer (indicando que un comprador puede tener muchos pedidos) incluye estas columnas orderdate (fecha o cadena, dependiendo de tu preferencia) orderstatus (cadena) creando la clase “orderdetails” finalmente, crea una clase llamada orderdetails agrega dos columnas pointer order → referencias a order product → referencias a product luego, agrega las columnas restantes quantity (número) unitprice (número) esta configuración permite una relación de muchos a muchos entre order y product a través de orderdetails , ya que cada pedido puede incluir múltiples productos, y cada producto puede aparecer en múltiples pedidos visualizando las relaciones aquí hay un diagrama de entidad relación (erd) simplificado que refleja las clases y sus punteros dbschema2 una vez que estas clases estén en su lugar, puedes manejar registros y inicios de sesión a través de la clase user , crear registros especializados de comprador o vendedor para diferentes tipos de usuarios, y almacenar información de productos o pedidos con referencias de clave externa claras al estructurar tu base de datos de esta manera, obtienes un diseño limpio y mantenible para cualquier aplicación de comercio electrónico con tu esquema en su lugar, estás listo para configurar la autenticación y autorización para restringir quién puede listar productos, realizar pedidos o llevar a cabo tareas administrativas el siguiente paso te mostrará cómo configurar flujos de registro e inicio de sesión seguros que se basan en los roles y clases que acabas de definir implementando autenticación con back4app la autenticación segura es central en cualquier plataforma de comercio electrónico, ayudándote a proteger cuentas de usuario, detalles de pago y datos personales back4app simplifica esto con múltiples métodos, desde combinaciones clásicas de nombre de usuario/contraseña hasta inicios de sesión sociales o flujos basados en tokens, asegurando que puedas ofrecer a tus compradores una experiencia sencilla y segura para configurar la autenticación en tu aplicación de comercio electrónico, utilizarás código en la nube el código en la nube amplía las capacidades de tu backend al permitirte escribir lógica de negocio personalizada sin tener que alojar tus propios servidores esto significa que puedes validar pedidos, calcular tarifas o activar notificaciones en eventos específicos, completamente dentro de la infraestructura de back4app es una forma ideal de manejar transacciones sensibles o procesos de datos que necesitan un control estricto y una ejecución rápida para habilitar el código en la nube en back4app, abre el panel de control de tu aplicación y localiza la cloud code sección find cloud code cuando hagas clic en cloud code , verás un main js donde puedes comenzar a implementar funciones personalizadas código en la nube para implementar el flujo de autenticación en back4app, necesitarás desplegar algunas funciones en tu código en la nube para registrar usuarios, iniciar sesión y cerrar sesión registrar un nuevo usuario (comprador por defecto) para registrar un nuevo usuario, utiliza el método de registro de parse establece campos estándar como nombre de usuario , contraseña , y correo electrónico , e incluye un campo personalizado para indicar el rol ya sea comprador o vendedor por defecto, a los nuevos usuarios se les asigna el rol de comprador hasta que decidan cambiarlo para comenzar, crea un auth js archivo en el directorio de la nube de tu código y agrega el bloque de código a continuación 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); } }); esta función en la nube maneja el registro de usuarios para compradores valida la entrada, crea un nuevo usuario de parse, asigna un rol ( buyer ), y almacena datos específicos del comprador en una clase de comprador separada iniciar sesión usuarios para autenticar usuarios, llama al método incorporado de parse parse user login y devuelve el token de sesión al cliente agrega el siguiente código a tu auth js archivo para implementar esta lógica en tu backend de código en la nube 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"); } }); esta función toma un correo electrónico y una contraseña del cliente, intenta autenticar al usuario y devuelve el token de sesión si tiene éxito si la cuenta está marcada como deshabilitada, bloquea el acceso y lanza un error claro cerrar sesión para implementar la función de cerrar sesión para tu backend, agrega el bloque de código a tu auth js archivo 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' }; }); esto finaliza de manera segura la sesión en el backend, evitando el uso posterior del token con estas funciones de cloud code en su lugar, ahora tienes un sistema de autenticación seguro que registra usuarios con lógica basada en roles autentica y autoriza el acceso utilizando tokens de sesión vincula cuentas de usuario a registros específicos de compradores soporta flujos de inicio y cierre de sesión limpios aprovecha las herramientas integradas de sesión y verificación de correo electrónico de back4app construyendo la lógica de negocio para tu aplicación de comercio electrónico para gestionar usuarios, productos, carritos y transacciones en tu plataforma de comercio electrónico, definirás una serie de funciones de cloud code en back4app estas funciones te permiten crear, leer, actualizar y eliminar (crud) recursos como vendedores, productos y pedidos mientras mantienes un control de acceso seguro vinculado a los roles de usuario a continuación se presenta un conjunto de funciones de cloud que demuestra cómo trabajar con entidades clave vendedor , producto , carrito , pedido , y detallesdelpedido cada función maneja una operación específica en el backend y asegura que se apliquen los permisos a través de la validación de usuarios y verificaciones de roles vendedor crea un perfil de vendedor para un usuario que desea ofrecer productos en la plataforma creando un vendedor esta función actualiza el rol del usuario actual a vendedor y crea un vendedor registro con información de la tienda para implementar esto en tu código en la nube, primero crea un seller js archivo y agrega el bloque de código a continuación 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); } }); esto asegura que solo los usuarios autenticados puedan convertirse en vendedores, y vincula el vendedor registro al usuario correspondiente a través de un puntero producto los productos son listados por los vendedores y pueden ser navegados, consultados y comprados por los compradores estas funciones permiten a los vendedores crear, recuperar, actualizar y eliminar sus productos, y también proporcionan acceso a los productos a los compradores creando un producto esta función agrega un nuevo producto para un vendedor que ha iniciado sesión y adjunta hasta tres imágenes del producto para implementar en tu código en la nube, crea un product js archivo y agrega el bloque de código a continuación 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}`); } }); esta función verifica que el usuario haya iniciado sesión y tenga un rol de vendedor, que exista un seller objeto correspondiente, y que no se envíen más de tres imágenes una vez validado, almacena el producto y lo vincula al vendedor consultando todos los productos esta función recupera todos los productos en el sistema, que se pueden usar para construir una tienda pública para implementar esto en tu código en la nube, agrega el bloque de código a continuación a tu products js archivo 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}`); } }); esta función obtiene productos con la usemasterkey bandera, y los formatea para el consumo en el frontend consultando un solo producto utiliza esta función al mostrar información detallada del producto a los compradores para implementar esto en tu código en la nube, agrega el bloque de código a tu products js archivo 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}`); } }); esta función devuelve detalles completos del producto para un artículo verifica que se pase un productid válido y asegura que el solicitante haya iniciado sesión consultando los productos del vendedor esta función permite a un vendedor recuperar todos sus propios productos para implementar esto en tu código en la nube, agrega el bloque de código a tu products js archivo 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}`); } }); esta función confirma que el usuario es un vendedor, localiza el seller registro asociado y consulta la product clase utilizando un puntero al vendedor los vendedores utilizan esto para obtener todos sus propios productos eliminando un producto esta función asegura que solo el vendedor que creó un producto puede eliminarlo para implementar esto en tu código en la nube, agrega el bloque de código a continuación a tu products js archivo 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}`); } }); esta función confirma la propiedad del usuario y luego elimina el producto de la base de datos actualizando un producto permitir a los vendedores modificar los detalles de un producto utilizando esta función para implementar esto en tu código en la nube, agrega el bloque de código a continuación a tu products js archivo 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}`); } }); asegura que el usuario sea un vendedor, confirma la propiedad del producto y actualiza solo los campos que se proporcionan en la solicitud carrito las funciones del carrito permiten a los compradores gestionar los artículos que pretenden comprar estas funciones incluyen agregar al carrito, actualizar cantidades, ver contenidos y eliminar artículos agregar al carrito esta función agrega un producto al carrito del comprador o actualiza la cantidad si ya existe para implementar esto, crea un cart js archivo y agrega el bloque de código a continuación 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}`); } }); asegura que el usuario esté autenticado, valida el producto, actualiza la lista de artículos y recalcula el precio total del carrito consultando el carrito recupera el contenido del carrito del usuario actual, incluyendo detalles del producto y subtotales para implementar esto, añade el bloque de código a tu cart js archivo 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, }; }); esta función utiliza include("items product") para obtener datos de productos anidados en una sola consulta editando el carrito actualiza la cantidad de un artículo en el carrito o elimínalo por completo si la nueva cantidad es cero para implementar esto, agrega el bloque de código a continuación a tu cart js archivo 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}`); } }); revalida todos los precios de los productos durante la actualización para asegurar la total precisión eliminando del carrito esta función elimina un producto del carrito del usuario para implementar esto, agrega el bloque de código a tu cart js archivo 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}`); } }); filtra el artículo del array del carrito y recalcula el total antes de guardar orden estas funciones gestionan el proceso de pedido, desde la creación de pedidos hasta la obtención del historial de pedidos de un vendedor creando un pedido esta función convierte el carrito del comprador en un pedido oficial para implementar esto, crea un order js archivo y agrega el bloque de código a continuación 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}`); } }); valida al comprador, verifica la disponibilidad de stock, reduce el inventario de productos, ahorra tanto pedido como detallesdelpedido , y limpia el carrito después de un pedido exitoso obteniendo pedidos del vendedor esta función recupera todos los pedidos que incluyen productos vendidos por el vendedor actual para implementar esto, agrega el bloque de código a tu order js archivo 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}`); } }); ubica productos propiedad del vendedor, consulta orderdetails para esos productos, obtiene los pedidos correspondientes y devuelve una estructura simplificada que incluye la información del comprador actualizando el estado del pedido esta función alterna el estado de un pedido entre “pendiente” y “completado ” para implementar esto, agrega el bloque de código a tu order js archivo 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}`); } }); asegura que solo los vendedores puedan realizar esta acción y que el pedido exista antes de actualizar el estado estas funciones de backend le dan a tu aplicación de comercio electrónico la capacidad de gestionar de manera segura todas las operaciones centrales listados de productos, carritos de compradores, pedidos e inventario de vendedores, directamente dentro de back4app utilizando cloud code para asegurarte de que puedes acceder a estas funciones en la nube externamente, necesitas registrar todos tus archivos de código en la nube en tu main js archivo, puedes hacerlo agregando el bloque de código a continuación a tu main js archivo //main js require(" /auth js") require(" /cart js") require(" /order js") require(" /product js") require(" /seller js") creación del frontend para construir visualmente tu tienda de comercio electrónico, utilizarás v0 dev para hacer esto, comienza visitando v0 dev http //v0 dev crea una cuenta si aún no tienes una una vez que tu cuenta esté configurada, puedes comenzar a crear tu frontend para crear tu frontend, ingresa el siguiente aviso create an e commerce web application with authentication features and a buyer and seller feature el aviso construirá una aplicación de comercio electrónico next js con las características solicitadas crear aplicación ecommerce usando la función de vista previa, puedes navegar a través de la aplicación para confirmar que todo funciona como se espera si hay algunas complicaciones o deseas agregar más características, puedes pasar otro aviso y v0 modificará la aplicación por ejemplo, pasa el aviso the seller can create, add, delete and update products este aviso modificará la aplicación, creando páginas donde el vendedor puede realizar operaciones crud modificar aplicación ecommerce finalmente, pasa el aviso 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) este aviso hará las ediciones finales a la aplicación para obtener una vista previa de la aplicación modificada, haz clic en el ver botón en la sección resaltada en la imagen de arriba una vez que estés seguro de que la aplicación es lo que deseas, el siguiente paso es llevar el proyecto a tu dispositivo local para hacer esto, haz clic en el botón de descarga que v0 genera con la respuesta del aviso botón de descarga hacer clic en el botón revelará un menú desplegable con un enlace y un botón de descarga zip menú desplegable a continuación, haz clic en el botón de descarga zip una vez que hayas terminado de descargar el zip, abre tu terminal y crea una nueva carpeta llamada ecommerce app en tu directorio preferido mkdir ecommerce app ahora extrae el contenido de la carpeta zip en la carpeta ecommerce app navega al directorio ecommerce app en tu terminal e instala las dependencias necesarias para hacer esto, ejecuta el siguiente comando cd ecommerce app npm install después de instalar las dependencias, ejecuta el npm run dev comando en tu terminal para ver el proyecto en tu servidor localhost integrando tu frontend con tu backend para conectar tu frontend con las funciones de cloud code en tu backend de back4app, utilizarás el sdk de javascript de parse el sdk te permite autenticar usuarios, llamar funciones de backend e interactuar con los modelos de datos de tu aplicación de manera segura y eficiente para configurar el sdk, ejecuta el siguiente comando en el directorio de tu proyecto en tu terminal npm install parse luego crea un lib/parse js archivo para configurar la conexión en este archivo, ingresa el bloque de código a continuación 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; reemplaza your app id y your javascript key con las credenciales que se encuentran en tu panel de back4app bajo app settings esta configuración básica asegura que el sdk sepa cómo conectarse a tu proyecto específico ahora que has conectado tu frontend a tu backend, puedes comenzar a escribir funciones para llamar a las funciones de código en la nube que definiste en tu aplicación de back4app autenticación en el cliente esta sección muestra cómo manejar el registro de usuarios, inicio de sesión y cierre de sesión en tu frontend utilizando el sdk de parse cada función corresponde a una función de cloud code o método de sdk que has implementado en tu backend de back4app en tu aplicación, el app/auth/register directorio contiene la lógica para registrar usuarios en el page tsx define el formdata estado este estado contendrá las credenciales necesarias para registrar a un usuario el formdata estado debería verse así const \[formdata, setformdata] = usestate({ name "", email "", password "", confirmpassword "", shippingaddress "", paymentinfo "", }); con las credenciales pasadas al formdata , puedes llamar a la signupuser función en la nube que definiste en tu aplicación back4app asegúrate de importar parse desde el 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); } } esta función se ejecutará cuando envíes el formulario de registro llama a la signupuser función en la nube definida en cloud code la función pasa las credenciales del usuario y datos específicos del comprador (como información de envío y pago) finalmente, registra la respuesta si la operación es exitosa o imprime un error si falla iniciando sesión de usuarios para iniciar sesión a un usuario, utiliza la loginuser función de código en la nube en tu backend navega a la app/auth/login directorio en tu aplicación dentro del page tsx archivo, v0 habrá creado el estado que contiene las credenciales del usuario que necesitas para iniciar sesión, solo necesitas pasar esas credenciales a la loginuser función por ejemplo 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); } }; esta función invoca la función en la nube loginuser , enviando las credenciales de inicio de sesión del usuario al servidor después de recibir un token de sesión válido en respuesta, utiliza parse user become para autenticar al cliente y establecer la sesión como perteneciente al usuario que ha iniciado sesión cerrar sesión de usuarios para cerrar sesión de forma segura, llamarás tanto a parse user logout() como a tu función personalizada logoutuser en el código de la nube esto asegura que el token de sesión se borre tanto en el cliente como que se invalide en el servidor encontrarás el botón de cerrar sesión en tu componente de encabezado este componente estará en tu components carpeta en el directorio raíz en el componente, define esta función 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 }; esta función cerrará sesión de un usuario y borrará la sesión tanto en el cliente como en el servidor en la parte jsx del componente, vincula la función al botón de cerrar sesión usando el onclick evento por ejemplo \<dropdownmenuitem onclick={handlelogout}> logout \</dropdownmenuitem> incorporación de vendedores esta sección muestra una función para permitir a los compradores actualizar su cuenta y registrarse como vendedores en tu aplicación, navega al app/seller/register directorio en este directorio, encontrarás tu page tsx archivo donde definirás la función que llama a la createseller función en la nube esta función es responsable de crear un perfil de vendedor para el usuario actual en el page tsx archivo, modifica el estado formdata para que se vea así const \[formdata, setformdata] = usestate({ phone "", bio "", businessname "", }); reemplaza la lógica en la función handlesubmit creada por v0 con la lógica a continuación 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); } }; llama a esta función al enviar el formulario para crear un perfil de vendedor para tus usuarios gestión de productos utiliza estas llamadas de función en tu frontend para gestionar operaciones de productos como vendedor creando un producto para llamar a la función de código en la nube que agrega un producto a la base de datos, localiza el app/seller/products/new directorio dentro de este directorio está tu page tsx archivo, en este archivo hay un formulario este formulario toma la información del producto, incluyendo imágenes modifica el producto estado para que se vea así const \[product, setproduct] = usestate({ name "", price "", description "", stock "", status "active", }); también crea un estado para mantener tus imágenes const \[images, setimages] = usestate\<file\[]>(\[]); ahora, escribe una función para manejar la adición de las imágenes a la base de datos esta función debería verse así 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); } }; vincula esta función a la entrada responsable de la carga de archivos utilizando el onchange evento a continuación, define la función handlesubmit esta función llama al addproduct código en la nube mientras pasa la información necesaria así 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); } }; esta llamada envía los datos del producto—incluidas las imágenes—al backend para crear un nuevo listado obtener todos los productos esta llamada recupera todo el catálogo de listados de productos públicos o un feed de la página de inicio para crear la función que llama a la fetchallproducts función en la nube, navega al app/products directorio en el page tsx archivo, agrega este código 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; } } este bloque de código arriba define una interfaz para los productos y un products estado la getallproducts función llama a la función en la nube fetchallproducts para obtener todos los productos en la base de datos ten en cuenta que necesitas llamar a la getallproducts función arriba dentro de un useeffect() hook para obtener y renderizar productos al cargar la página así useeffect(() => { getallproducts() then((products) => { setproducts(products); }) catch((error) => { console error("error fetching products ", error); }); }, \[]); obtener un producto único esta llamada recupera todos los detalles sobre un producto específico navega a la \[id] carpeta en tu app/products directorio esta carpeta contiene el page tsx archivo que contendrá la lógica para obtener los detalles de un solo producto en el page tsx archivo, escribe este código 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); }); }, \[]); este bloque de código define la interfaz para el objeto producto, configura una variable de estado product con valores predeterminados la getsingleproduct función llama a tu getsingleproduct función de código en la nube usando un productid de los parámetros de la ruta este useeffect hook se ejecuta una vez cuando se monta el componente actualizar un producto cuando un vendedor edita un producto, llama a esta función con los campos actualizados para actualizar productos, necesitas un formulario con campos de entrada que recojan los nuevos datos, puedes encontrar este formulario en el page tsx archivo ubicado en el app/seller/products/\[id]/edit directorio antes de actualizar un producto, necesitas obtener el producto y para hacer esto añade este código a tu page tsx archivo 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(); }, \[]); este código obtiene los detalles de un solo producto de tu backend de back4app con la getsingleproduct función de código en la nube y almacena los detalles en el estado del componente product para mostrar como el valor predeterminado en tu formulario antes de modificarlo después de obtener los detalles del producto, puedes cambiar los detalles usando el formulario después de llenar el formulario, enviar el formulario llamará a una handlesubmit función que contendrá la lógica para actualizar tu producto tu handlesubmit función debería verse así 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); } }; esta función llama a tu updateproduct función de cloud code y envía un objeto con los datos actualizados del producto eliminar un producto usa esta función para eliminar un producto después de la confirmación del vendedor para eliminar un producto, necesitas agregar una handledelete función que contenga la lógica necesaria para eliminar el producto definirás la handledelete función en el page tsx archivo en el app/seller/products/\[id]/edit directorio 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); } }; la handledelete función primero confirma la intención del usuario antes de llamar a la deleteproduct función de código en la nube definida en tu backend vincula la handledelete función al botón de eliminar en la parte jsx del componente por ejemplo \<button type="button" variant="destructive" onclick={handledelete} \> \<trash2 classname="h 4 w 4 mr 2" /> delete product \</button> obtener productos del vendedor usa esto para obtener todos los productos propiedad del vendedor que ha iniciado sesión actualmente definirás la función para manejar la obtención de los productos del vendedor en el page tsx archivo en el app/seller/dashboard directorio en el archivo, escribe este código 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(); }, \[]); este bloque de código define el products estado y utiliza el useeffect gancho para llamar a la fetchproducts función una vez al cargar la fetchproducts función llama a la getsellerproducts función de código en la nube y actualiza el products estado con el resultado de la llamada gestión del carrito estas llamadas permiten a los compradores gestionar su carrito de compras antes de realizar un pedido agregar al carrito esta llamada agrega un producto seleccionado al carrito del usuario o incrementa su cantidad localiza el page tsx archivo en el app/products directorio y agrega las siguientes líneas de código 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); } } la función handleaddtocart acepta productid y cantidad opcional como argumentos y llama al addtocart código en la nube en tu backend esta función debería ejecutarse cuando tus usuarios hagan clic en el botón "agregar al carrito" en la tarjeta de tu producto por ejemplo \<button classname="w full" size="sm" onclick={() => handleaddtocart(product id)}> \<shoppingcart classname="h 4 w 4 mr 2" /> add to cart \</button> en el archivo, escribe este código ver carrito utiliza esto para obtener el contenido del carrito y renderizar un resumen del carrito en vivo para hacer esto, navega al page tsx archivo en el app/cart directorio dentro de este archivo, agrega el bloque de código a continuación 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(); }, \[]); el bloque de código anterior define la forma de los datos del carrito en el frontend con la interfaz cartitem , define el estado cartitems que contiene los artículos del carrito también utiliza useeffect para activar la función fetchcart una vez al cargar la página la fetchcart función llama a la función de código en la nube getcart y recupera el carrito de tu backend utiliza el método map para convertir el formato del backend al formato del frontend antes de guardar los datos del carrito procesados en el estado cartitems actualizar artículo del carrito esta llamada cambia la cantidad de un producto específico en el carrito dentro del page tsx archivo en el app/cart directorio, encontrarás una updatequantity función reemplaza esa función con la siguiente 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); } }; esta función toma dos parámetros, productid y la cantidad actualizada que el usuario desea establecer newquantity llama a tu updatecart función en la nube y envía tanto el productid como el newquantity como parámetros vinculas esta función a los botones +/ usando el onclick evento así \<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> eliminar del carrito elimina un artículo completamente del carrito para hacer esto, agrega el bloque de código a continuación al page tsx archivo en el app/cart directorio dentro de este archivo 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); } }; esta función, removeitem , elimina un producto específico del carrito del usuario llamando a la función en la nube removefromcart en el backend la función también actualiza el estado local del carrito en el frontend para reflejar el cambio vincula esta función al botón de "eliminar artículo", así \<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> gestión de pedidos estas funciones manejan la creación y seguimiento de pedidos para compradores y vendedores crear un pedido esto crea un pedido a partir del contenido actual del carrito del usuario también defines esta función en el page tsx archivo en el app/cart directorio la función que contiene la lógica para crear el pedido debería verse así 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); } }; esta función, handleorder , maneja el proceso de pago al realizar un pedido a través de tu backend de back4app verifica si un usuario ha iniciado sesión, luego llama a la createorder función en la nube para convertir el carrito actual del usuario en un pedido oficial para llamar a esto en el pago, vincula la función al botón "checkout" utilizando el onclick evento por ejemplo \<button classname="w full" onclick={handleorder}>proceed to checkout\</button> ver pedidos del vendedor los vendedores pueden usar esta llamada para ver pedidos que incluyen sus productos define esta función en el page tsx archivo en el app/seller/dashboard directorio agrega las siguientes líneas de código al page tsx archivo 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); } }; este código recupera una lista de pedidos que incluyen los productos del vendedor y los almacena en el estado local ordersdata para mostrarlos en un panel de control del vendedor o vista de gestión de pedidos asegúrate de llamar a la función en un useeffect hook para que la función se ejecute una vez al cargar la página actualizar un pedido esto alterna el estado de un pedido entre "pendiente" y "completado" define esta función en el page tsx archivo en el app/seller/dashboard directorio la función debería verse así 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); } };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); } };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); } }; esta función, handleupdate , actualiza el estado de un pedido existente llamando a la función en la nube llamada completeorder en tu backend de back4app vincula esta función a un botón de "editar" en la parte jsx del componente así \<button variant="ghost" size="icon" onclick={() => {handleupdate(order id)}}> \<pencil classname="h 4 w 4" /> \<span classname="sr only">view\</span> \</button> desplegando el frontend en contenedores de back4app los contenedores de back4app ofrecen una forma simplificada de empaquetar y desplegar tu aplicación frontend en lugar de manejar servicios de alojamiento separados, puedes almacenar todas las dependencias dentro de una imagen de docker, asegurando un rendimiento consistente y simplificando el mantenimiento este enfoque basado en contenedores es especialmente útil para aplicaciones de next js, donde puedes optimizar las compilaciones para velocidad y fiabilidad para contenerizar tu aplicación, crea un dockerfile para definir cómo se construye y se sirve tu aplicación a continuación se muestra un ejemplo de dockerfile para una aplicación de next js # 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"] después de crear tu dockerfile, crea un dockerignore archivo y agrega estos comandos # 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 ahora puedes construir y probar tu aplicación localmente para hacer esto, ejecuta el siguiente comando en tu terminal docker build t ecommerce app docker run p 3000 3000 ecommerce app abre http //localhost 3000 para asegurarte de que tu sitio funcione correctamente una vez que hayas verificado que todo funciona como se espera localmente, es hora de subir tu código a github y desplegarlo a través de back4app asegúrate de que tu código esté comprometido y subido a un repositorio de github esto permitirá que back4app acceda a tu proyecto para el despliegue en tu cuenta de back4app, ve a tu panel de control y haz clic en el panel de control menú desplegable en la parte superior de la pantalla dashboard menu desde el menú desplegable, selecciona plataforma de despliegue web web deployment platform esto te llevará a la página de despliegue de la aplicación web deploy web application page haz clic en el desplegar una aplicación web botón para iniciar el proceso de despliegue link github repo luego, haz clic en importar repositorio de github y elige el repositorio que contiene tu dockerfile asigna un nombre a tu proyecto (por ejemplo, ecommerce back4app) sigue la configuración guiada para construir y desplegar tu aplicación una vez que se complete el despliegue, back4app mostrará una página de confirmación como esta despliegue exitoso el área resaltada en la imagen anterior es la url donde tu aplicación está activa puedes usarla para ver y probar tu aplicación directamente en un navegador web una vez desplegado, utiliza el panel de control de back4app para monitorear los registros de construcción, rastrear la salud del contenedor y revertir a versiones anteriores si es necesario el panel de control muestra actualizaciones en tiempo real sobre el estado del contenedor, lo que facilita detectar errores y mantener un entorno estable para tus usuarios con los contenedores, obtienes una solución de frontend flexible y portátil que se integra a la perfección con tu backend de back4app, allanando el camino para lanzamientos consistentes y sin complicaciones puedes visitar el sitio web de comercio electrónico construido en este tutorial aquí https //ecommerceback4app mcphit37 b4a run/ conclusión felicidades, has ensamblado cada capa de un stack de comercio electrónico listo para producción y probado en batalla configuración del backend desde la provisión de tu cuenta de back4app hasta la modelación de usuarios, productos y pedidos seguridad y apis implementación de autenticación robusta y exposición de tus datos a través de endpoints rest y graphql lógica de negocio y actualizaciones en tiempo real automatización de flujos de trabajo con cloud code y transmisión de cambios en vivo a través de livequery despliegue del frontend conexión del sdk de javascript y envío de una tienda next js en contenedores de back4app ¿qué sigue? sumérgete en la documentación de back4app https //www back4app com/docs y en la guía de la plataforma parse https //docs parseplatform org para referencias detalladas, o únete al foro de la comunidad para obtener consejos avanzados y aplicaciones de muestra de mantenedores y otros desarrolladores esta base es solo el comienzo; amplíala aún más integrando webhooks y trabajos programados, conectando pasarelas de pago o construyendo una aplicación móvil complementaria sigue iterando, refactorizando y evolucionando tu base de código, y observa cómo tu tienda crece junto a tus ambiciones