An e-commerce platform built with React, TypeScript, and Vite, leveraging modern web development practices and a component-driven architecture.
- What & Why
- Technical Deep Dive
- API & Data Fetching
- Key Features
- Project Structure
- Installation
- Usage
- Key Functionality and Usage Examples
- Contributing
- License
- Contact
VzCommerce is a lightweight, sales-focused ecommerce platform designed for small businesses that close deals through WhatsApp.
Instead of forcing the entire checkout process inside the website, VzCommerce acts as a seamless bridge: customers browse a full product catalog, view price, stock and promotions, and once they decide to buy, the platform automatically routes the order to WhatsApp so the seller and customer can finalize payment, shipping, and details privately.
On the admin side, sellers get a complete dashboard with real-time analytics powered by Chart.js, dynamic tables with pagination for managing products, and a dedicated orders panel. It also includes an integrated AI assistant specialized in digital business and sales to provide guidance, insights, and optimization tips.
I noticed that many small sellers prefer finalizing their sales through WhatsApp, where they can negotiate, build trust, and adapt pricing or delivery on the fly. However, keeping a catalog updated manually, sending photos, prices, descriptions one by one is tedious and unscalable.
VzCommerce was built to solve that gap: give customers a comfortable, organized place to explore the entire catalog, while preserving the seller's preferred workflow of closing the sale in private through WhatsApp. It blends the convenience of a modern storefront with the flexibility of conversational selling.
The main challenge was to create an ecommerce platform that feels complete and professional, apply Clean Architecture with design patterns, and implement a robust testing strategy with +500 tests. At the same time, building a robust admin panel with real-time analytics, dynamic data tables, and an AI assistant required careful architecture, and clean, maintainable code.
- Product Listings: Display of products with details such as name, description, price, and images.
- Category Management: Categorizing products for easy navigation.
- Shopping Cart: Add, remove, and manage products in a shopping cart.
- Admin Authentication: Secure admin login.
- Admin Panel: Administrative interface for managing products, categories, and orders with Data-Tables (tanstack/react-table).
- Checkout Process: Streamlined checkout process with token-based validation.
- AI Assistant: Private admin AI to help manage the store.
- WhatsApp Automated Message: WhatsApp notifications for order confirmations.
- Image Handling: Image transformation, WebP conversion, and cloudinary uploads, and lazy loading for optimized performance.
- Real-time Analytics: Track statistics of the store with Chartjs.
- Modular Components: Reusable UI elements and organized architecture for maintainability.
- Optimized Build Process: Streamlined workflows with Vite, TailwindCSS, and TypeScript configurations.
- Secure API & Authentication: Robust route protection, session management, and user authentication.
- State & Data Management: Centralized store with Redux Toolkit, React Query, and data validation schemas.
- Flexible Routing & Admin Tools: Organized navigation, admin dashboards, and private pages.
The application follows a Clean Architecture with layers like Domain, Application, Infrastructure and Presentation.
If you are interested in what is a clean architecture and how you can use it, please check my free book, in Spanish.
Arquitecturas y Patrones - Valentin Zoia
| Layer | Technology | Key Packages |
|---|---|---|
| Frontend | React 19, TypeScript, Vite | react, react-router-dom, @reduxjs/toolkit, @tanstack/react-query |
| UI Framework | Tailwind CSS 4, Radix UI, Shadcn | tailwindcss, @radix-ui/react-*, lucide-react, |
| Data Table | Tanstack React Table and Shadcn | @tanstack/react-table, |
| Form | React Hook Form and Zod for Validations | react-hook-form, zod, |
| State Management | Redux Toolkit, React Query | @reduxjs/toolkit, react-redux, @tanstack/react-query |
| Backend | Node.js, Express 5, TypeScript | express, typescript, tsx |
| Database | MongoDB with Prisma ORM | @prisma/client, prisma |
| Authentication | JWT, Bcrypt | jsonwebtoken, bcryptjs |
| External APIs | WhatsApp Web.js, OpenAI | whatsapp-web.js, openai |
| Testing | Jest, Supertest | jest, supertest |
| Development | Vite, ESLint | vite, eslint |
This project implements a hybrid state management strategy that separates server state from client state:
| State Type | Technology | Use Case |
|---|---|---|
| Server State | TanStack Query (React Query) | Products, Categories, Orders, Auth data |
| Client State | Redux Toolkit | Shopping cart (needs persistence) |
| Form State | React Hook Form | All forms with Zod validation |
| UI State | React useState | Local component state |
The decision to use both technologies was intentional:
- React Query: Handles server state with automatic caching, background refetching, optimistic updates, and cache invalidation. Perfect for data that comes from the API.
- Redux Toolkit: Used exclusively for the shopping cart because it needs to persist across sessions (localStorage) and has complex synchronous logic with reducers.
// React Query - Server State
const { data, isLoading } = useProducts({
page: 1,
limit: 10,
category: 'shoes',
priceMin: 50,
priceMax: 200,
sortBy: 'price',
sortDir: 'asc'
});
// Redux Toolkit - Client State (Cart)
const { items, addItem, removeItem, clearCart } = useCartActions();The backend follows Clean Architecture with 4 clearly defined layers:
src/
βββ Domain/ # Entities, Interfaces, DTOs (innermost layer)
βββ Application/ # Use cases, Business logic services
βββ Infrastructure/ # External implementations (Prisma, APIs, Adapters)
βββ Presentation/ # Routes, Controllers, Middlewares
Principles applied:
- π Dependency Inversion: External layers depend on internal ones
- π§ͺ Testability: Each layer can be tested in isolation
- π¦ Separation of Concerns: Responsibilities clearly defined
| Pattern | Implementation | Location |
|---|---|---|
| Repository | Data access abstraction | infrastructure/repositories/* |
| Builder | Complex object creation | ProductBuilder, OrderBuilder, OrderItemBuilder |
| Adapter | Interface conversion | OrderSendMessageToCustomer.impl.ts |
| Factory | Test data generation | Test helpers |
| Middleware | Cross-cutting concerns | AuthMiddleware, ValidationMiddleware |
| Dependency Injection | Loose coupling | Constructor injection in services |
| Optimization | Implementation |
|---|---|
| Lazy Loading | React.lazy() + <Suspense> for routes and heavy components |
| Image Lazy Loading | Custom <Lazy> component with IntersectionObserver |
| Debounced Search | useDebounce hook (300ms delay) to avoid excessive API calls |
| Skeleton Loaders | Visual placeholders during data fetch |
| React Query Caching | staleTime: 5min, gcTime: 10min |
| Optimistic Updates | Immediate UI updates with automatic rollback on error |
| Image Optimization | WebP conversion, Cloudinary CDN |
| Component Memoization | React.memo where needed |
| Feature | Implementation |
|---|---|
| JWT in Cookies | httpOnly, secure, sameSite cookies |
| Helmet.js | HTTP security headers |
| CORS | Configurable allowed origins |
| Rate Limiting | express-rate-limit (100 requests/15min) |
| bcryptjs | Password hashing |
| Zod Validation | Input validation on both client and server |
| Auth Middleware | Token verification on protected routes |
The backend has 59 test files with over 11,000 lines of test code:
| Test Type | Coverage |
|---|---|
| Unit Tests | Services, DTOs, Entities |
| Integration Tests | Repositories, Controllers |
| E2E Tests | Full flows (auth β create β update β delete) |
| Black Box Tests | Testing without internal code access |
Test Coverage by Module:
| Module | Unit | Integration | E2E |
|---|---|---|---|
| Auth | β | β | β |
| Products | β | β | β |
| Categories | β | β | β |
| Orders | β | β | β |
| Middlewares | β | β | β |
All GET endpoints support pagination and filtering:
{
page: number; // Current page
limit: number; // Items per page (take)
search?: string; // Text search
category?: string; // Filter by category
priceMin?: number; // Minimum price
priceMax?: number; // Maximum price
inStock?: boolean; // Only in-stock products
freeShipping?: boolean;
featured?: boolean;
promotion?: boolean;
new?: boolean;
size?: string;
sortBy?: 'price' | 'createdAt' | 'discountPercentage';
sortDir?: 'asc' | 'desc';
}The project includes many custom hooks for code reuse:
| Hook | Purpose |
|---|---|
useProducts() |
Fetch products with filters |
useProductsFilters() |
Filter state management |
useProductById() |
Single product fetch |
useProductMutations() |
CRUD operations |
useCategories() |
Categories fetch |
useCategoryMutations() |
Categories CRUD |
useOrders(), useOrderById() |
Orders fetch |
useOrderMutations() |
Orders CRUD |
useStoreCustomer() |
Store data |
useAuthMutations() |
Login/Logout |
useSession() |
Session verification |
useCartActions() |
Cart management |
useCheckout() |
Checkout process |
useAIMutations() |
AI chat |
useDebounce() |
Avoid excessive requests |
useImageCropper() |
Image cropping |
useMobile() |
Responsive detection |
useCheckoutForm() |
Checkout form |
useProductForm() |
Product form |
useOrderForm() |
Order form |
useInstallments() |
Installment calculation |
useImageUpload() |
Cloudinary upload |
- WhatsApp Web.js for session management
- QR authentication for linking
- Message states: PENDING β SENT β RESPONDED β COMPLETED
- Automatic order confirmation messages
- Real-time connection events
- OpenAI SDK integration with GPT-4.1
- AI Chat Interface in admin panel
- AI Insights Cards for business analysis
- Custom endpoint support (compatible routers)
- Cloudinary direct upload with presets
- Automatic WebP conversion
- react-cropper for image resizing
- Browser-side compression before upload
- Multiple images per product (gallery)
- Real-time analytics with Recharts:
- Line Chart: Sales trends
- Bar Chart: Top products
- Pie Chart: Category distribution
- Area Chart: Monthly performance
- Dynamic tables with TanStack Table
- Sorting, filtering, pagination
- Order management
- Store configuration
The project is structured as a monorepo, with separate directories for the client and server.
βββ client/ # Frontend application
β βββ src/ # Source code
β β βββ components/ # React components
β β βββ guards/ # Route guards
β β βββ hooks/ # Custom hooks (25+)
β β βββ layouts/ # Layout components
β β βββ lib/ # Utilities, axios, zod schemas
β β βββ pages/ # Page components
β β βββ types/ # TypeScript types
β β βββ store/ # Redux store
β β βββ utilities/ # Utility functions
β β βββ data/ # API calls
β β βββ App.tsx # Main application component
β β βββ main.tsx # Entry point
β β βββ routes/ # Application routes
β βββ public/ # Static assets
β βββ package.json # Dependencies and scripts
β βββ tsconfig.json # TypeScript configuration
β βββ vite.config.ts # Vite configuration
βββ server/ # Backend application
β βββ src/ # Source code
β β βββ app.ts # Entry point
β β βββ server.ts # Server setup
β β βββ AI/ # AI Assistant feature
β β βββ Auth/ # Authentication
β β βββ Categories/ # Categories feature
β β βββ Checkout/ # Checkout feature
β β βββ Orders/ # Orders feature
β β βββ Products/ # Products feature
β β βββ StoreCustomers/ # Store customers
β β βββ shared/ # Shared modules
β βββ tests/ # Tests
β β βββ context/ # Unit & integration tests
β β βββ apps/ # E2E & black box tests
β β βββ helpers/ # Factories, mocks, helpers
β βββ package.json # Dependencies and scripts
β βββ tsconfig.json # TypeScript configuration
β βββ prisma/ # Prisma schema and migrations
βββ README.md # Project documentation
βββ .gitignore # Specifies intentionally untracked files
- Clone the repository:
git clone https://github.com/ValentinZoia/e-commerce.git
- Navigate to the client directory:
cd e-commerce/client - Install client dependencies:
npm install
- Navigate to the server directory:
cd ../server - Install server dependencies:
npm install
- Set up the database:
- Ensure that you have a MongoDB database running.
- Configure the database connection in the
.envfile in theserverdirectory.
DATABASE_URL="<your-mongodb-url>"- Generate the Prisma client:
npm run prisma:generate
- Navigate to the client directory:
cd client - Start the development server:
This will start the Vite development server, and you can access the application in your browser.
npm run dev
- Navigate to the server directory:
cd server - Start the development server:
npm run dev
cd server
npm test-
Product Display: Products are fetched and displayed using React components within the
client/src/componentsdirectory. Data is fetched using TanStack React Query. Example usage:import { useQuery } from '@tanstack/react-query'; import axios from 'axios'; const fetchProducts = async () => { const { data } = await axios.get('/api/products'); return data; }; const ProductsComponent = () => { const { data, isLoading, error } = useQuery('products', fetchProducts); if (isLoading) return <p>Loading...</p>; if (error) return <p>Error: {error.message}</p>; return ( <ul> {data.map(product => ( <li key={product.id}>{product.name} - {product.price}</li> ))} </ul> ); };
-
Form Handling: React Hook Form is used for managing forms, with Zod for schema validation. Example usage from the client side:
import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; const schema = z.object({ username: z.string().min(3).max(20), email: z.string().email(), }); type FormData = z.infer<typeof schema>; const MyForm = () => { const { register, handleSubmit, formState: { errors } } = useForm<FormData>({ resolver: zodResolver(schema) }); const onSubmit = (data: FormData) => console.log(data); return ( <form onSubmit={handleSubmit(onSubmit)}> <input type="text" {...register("username")} /> {errors.username && <span>{errors.username.message}</span>} <input type="email" {...register("email")} /> {errors.email && <span>{errors.email.message}</span>} <button type="submit">Submit</button> </form> ); };
-
Authentication: The application implements authentication using JWTs, with middleware for protecting routes. The
AuthGuardcomponent inclient/src/guards/auth.guard.tsxhandles route protection. -
Checkout Process: The checkout process is initiated using tokens, validated by the
CheckoutGuardinclient/src/guards/checkout.guard.tsx. The route/checkout/:tokenis used for checkout.
- Fork repository
- Create feature branch (
git checkout -b feature/AmazingFeature) - Commit changes (
git commit -m 'Add some AmazingFeature') - Push to branch (
git push origin feature/AmazingFeature) - Open Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Author: ValentΓn Zoia
- Email: zoiavalentin.dev@gmail.com
- LinkedIn: Profile
- Portfolio: Website
Built with β€οΈ and best practices


























