E-Commerce Web Application
Scalable E-Commerce Platform
A mobile-first commerce experience with secure Razorpay checkout, real-time inventory, order tracking, promotions, and a practical operations dashboard.

Project overview
This project transformed a basic online catalog into a complete commerce application serving both shoppers and operations staff. The scope included discovery and filtering, accounts, wishlists, cart pricing, secure payments, order tracking, inventory controls, promotions, and sales reporting. I worked across the React interface, Node.js API, MongoDB data model, Razorpay integration, and AWS delivery setup.
The guiding principle was simple: a shopper should be able to move from search to confirmed payment on a small screen without uncertainty, while administrators should be able to understand inventory and order state from one system.
Problem statement
The previous experience made users repeat work. Filters reset between category pages, the cart did not clearly explain discounts, and payment failures left customers unsure whether an order existed. Product availability was also checked too late, which produced avoidable cancellations during busy periods.
For operators, stock changes, refunds, and shipment updates were managed separately. That delayed customer communication and made sales reports difficult to reconcile. The replacement needed consistent pricing, resilient payment handling, accurate stock, and a fast mobile experience.
Solution
I designed a responsive React storefront with reusable product, price, promotion, and checkout components styled in TailwindCSS. Search and filter state lived in the URL, making results shareable and preserving context during navigation. Images were resized at upload, stored in S3, and served through CloudFront with responsive variants.
The Express API separated catalog, cart, order, payment, and administrative services. MongoDB schemas captured product variants and an immutable order price snapshot, preventing later catalog edits from changing historical totals. Compound indexes supported category, price, availability, and creation-date queries.
Checkout used a server-calculated total. The browser submitted product identifiers and quantities, never a trusted amount. A signed Razorpay webhook then moved a pending order to paid in an idempotent transaction:
if (await PaymentEvent.exists({ eventId: event.id })) return;
await confirmOrder({
orderId: event.payload.orderId,
gatewayPaymentId: event.payload.paymentId,
});
Inventory was reserved for a short window when checkout began and released after timeout or failure. This reduced overselling without locking stock indefinitely. Order-state changes produced email and in-app notifications through background workers, keeping the checkout response quick.
Key capabilities
- Product search, categories, faceted filters, variants, and stock indicators.
- Persistent cart and wishlist behavior for authenticated customers.
- Coupon rules with minimum totals, expiry, audience, and usage limits.
- Razorpay payment verification, retries, refunds, and event reconciliation.
- Customer order timeline with shipment and delivery notifications.
- Admin tools for products, bulk inventory, orders, returns, and revenue reports.
Outcomes
The shorter checkout and clearer failure recovery improved completed checkout conversion by 40% during the measured comparison period. Cart abandonment fell by 28%, helped by upfront delivery costs and persistent cart state. CDN-backed responsive images and route-level lazy loading kept the main shopping journey above a 90 Lighthouse performance score on representative mobile devices.
Operations gained a consistent order record from placement through refund. Inventory reservations reduced overselling incidents, while webhook reconciliation prevented duplicate fulfillment when the payment provider retried events.
Key engineering decisions
The cart remained a convenience record, while the order was the commercial record. Product names, selected variants, prices, taxes, discounts, and delivery charges were copied into the order at checkout, so later catalog edits could not rewrite customer history. Money used integer minor units throughout the API to avoid floating-point rounding errors. Promotion evaluation returned an explanation as well as a discount, making rejected coupons understandable in both storefront and support tools.
The first release used domain modules inside one Node.js application instead of separate microservices. Clear service interfaces and an outbox for notifications preserved future options without adding distributed transactions to a six-month build. Payment and fulfillment state machines rejected invalid backward transitions. This was especially valuable when delayed webhooks arrived after a manual support action: the event was recorded for reconciliation but could not quietly reopen or fulfill a cancelled order.
Related engineering work
For a larger marketplace variation, read the headless multi-vendor marketplace case study. The database decisions connect to MongoDB performance tuning, and the UI system follows the practices described in TailwindCSS best practices for scalable UI.