Buxom Cosmetics
Multi-tier e-commerce architecture with Prisma ORM and MySQL schemas.
What I Built#
I developed this project for a university web engineering course to practice building a decoupled, multi-tier e-commerce web application. The store is modeled after Buxom Cosmetics, featuring a customer-facing storefront, a shopping cart, user accounts, and an inventory management backend.
The project is organized into two separate repositories:
- Frontend: A single-page application built with React, TypeScript, and Redux Toolkit.
- Backend: A REST API built with Node.js, Express, Prisma ORM, and MySQL.
Core Features#
- Product Catalog: Browsing cosmetic items with category filters and product detail views showing item variants (shades, sizes, and pricing).
- Cart Management: Add, remove, and update item quantities with persistent state managed by Redux Toolkit.
- User Authentication: JWT-based sign-in and registration to protect customer order histories and administrative routes.
- Order Placement: A checkout flow that validates cart items against current inventory before confirming the sale.
Architecture#
React + TypeScript Client (Redux Toolkit)
│
▼
┌───────────────────────────────────┐
│ Express REST API │ (JWT Auth & Product Endpoints)
└─────────────────┬─────────────────┘
│
▼
┌───────────────────────────────────┐
│ Prisma ORM Client │ (Type-Safe Schema & Transactions)
└─────────────────┬─────────────────┘
│
▼
┌───────────────────────────────────┐
│ MySQL Database │ (Products, Variants, Orders, Users)
└───────────────────────────────────┘Technical Lessons & What I Learned#
1. Modeling Product Variants in Prisma
Cosmetics products often come in multiple variations (different shades, bottle sizes, and prices). Instead of flattening everything into a single wide table, I structured the schema with a Product parent table and a relational ProductVariant child table in Prisma. This made it easy to fetch product pages with nested include: { variants: true } while keeping inventory tracked accurately per shade.
2. Using Prisma Transactions for Checkout
When a customer confirms an order, the system must create an order record and decrement product stock numbers. If one step succeeds and the other fails, inventory counts get corrupted. I used Prisma's $transaction API to wrap the order creation and stock decrements into a single atomic operation, ensuring that changes either commit together or roll back cleanly.
3. Centralizing Cart State with Redux Toolkit
Managing cart state across navigation pages can quickly become messy with local component state. Setting up Redux Toolkit with a dedicated cartSlice kept cart logic predictable and allowed easy persistence to local storage while re-validating prices with the backend before checkout.