CASE STUDY / COMMERCE SYSTEM
Petify
Active iteration
From a storefront to a three-surface commerce system
Petify separates a customer storefront, seller operations dashboard and Express API into three independent applications. It covers product discovery, filtering, carts, orders, reviews, realtime support and operational analytics with React, Redux, Tailwind CSS, Node.js, MongoDB, Cloudinary, Docker and Caddy.
01 / PRODUCT SURFACES
Why split commerce into three applications?
Petify was not simply a product list. It had to organise three different experiences around the same users, products, orders and conversations: customers need a clear path from discovery to purchase, sellers need a dense operations workspace, and support needs low-latency communication. The project therefore separates the storefront, seller surface and API, then connects commerce and conversations through REST, Redux and Socket.IO.
- Separate the customer storefront, seller operations dashboard and Express API into independent application boundaries
- Create a continuous customer experience across discovery, carts, orders, reviews and support
- Use Redux, React Router and Tailwind to organise cross-screen state and responsive interfaces
- Give sellers one workspace for products, orders, metrics and customer conversations
02 / COMMERCE FLOW
How a purchase moves from discovery to operations
- 01
Discover
Customers start with the home banner, categories and product lists. The API returns latest, top-rated and discounted products, while the frontend shapes the discovery path.
- 02
Filter
The shop combines category, price range, rating, keyword and price sorting while keeping the same filters across grid/list views and pagination.
- 03
Decide
Product details bring together images, description, stock, discount, rating, reviews, related products and more products from the same seller.
- 04
Cart
Customers add products to a cart or wishlist, adjust quantities, check stock and provide shipping information at checkout.
- 05
Order
The order path creates a customer order and seller sub-orders, removes cart items and exposes status through the customer dashboard.
- 06
Operate
Sellers use the dashboard, products, categories, orders, payment stats and support views for daily operations, while Socket.IO surfaces active customers and messages.
03 / FRONTEND ENGINEERING
Product and engineering decisions visible in the code
- 01
Treat storefront, seller surface and API as product boundaries
ImplementationThe frontend and dashboard are independent Vite React applications. The backend owns the Express REST API, MongoDB, uploads and Socket.IO, while Caddy routes pet.linze.pro and seller.pet.linze.pro to the corresponding static assets and API.
ValueThe storefront and seller workspace can have different information density, navigation and interaction models while sharing one business data layer.
- 02
Organise cross-screen commerce state with Redux Toolkit
ImplementationThe storefront keeps separate auth, home, cart, order, dashboard and chat reducers. The dashboard has auth, product, category, seller, order and chat state of its own.
ValueProduct details, carts, orders, dashboards and conversations have stable state entry points instead of rebuilding the same cross-screen interactions in each page.
- 03
Design the seller workspace around daily operations
ImplementationThe dashboard combines protected routes, lazy loading, product and order tables, search, pagination, charts and a react-window virtual list for product, order, payment and support views.
ValueThe dashboard is not just an extension of the storefront: it gives product management, order processing, sales metrics and support their own high-density workflow.
- 04
Combine REST persistence with Socket.IO delivery
ImplementationChat controllers save Customer, Seller and Admin messages to MongoDB. Socket.IO tracks in-process connections and delivers messages to active recipients, while Redux updates the conversation state in the clients.
ValueQueryable history and low-latency interaction have separate responsibilities: REST provides durable reads and Socket.IO handles the online feedback path.
- 05
Make localisation, theme and responsiveness part of the UI foundation
ImplementationThe storefront uses react-i18next and browser-language detection for English and Chinese copy. Tailwind covers product, detail, cart and mobile layouts, while the dashboard uses ThemeProvider and a responsive sidebar.
ValueThe product is not limited to one language or desktop viewport; language, device size and visual preference have explicit places in the interface structure.
- 06
Include media and deployment in the delivery path
ImplementationFormidable receives product images and profile uploads, Cloudinary hosts media URLs, Docker Compose runs MongoDB and the backend, Makefile builds the two static applications, and Caddy provides HTTPS, SPA fallback and proxying.
ValueThe project covers content entry, static asset publishing, API routing and server deployment instead of stopping at a local development setup.
04 / CURRENT BOUNDARIES
A complete frontend experience, with transaction boundaries still to close
The storefront and seller workspace form a clear product skeleton. Identity boundaries, order consistency, realtime connections and the payment path are the most important next engineering problems.
- High priority
The order API still trusts too much client data
placeOrder receives userId, product structures, price and shipping information from the client. The code does not yet fully show server-side price reloading, stock validation, atomic inventory decrement, idempotency or a transaction boundary. The cart-to-order flow works, but it should not be presented as a strongly consistent transaction system.
- High priority
Customer API and role boundaries are not unified yet
Some cart, wishlist, review and order endpoints use a userId from the URL or request body, while dashboard routes mainly rely on a shared auth middleware. The next step is deriving identity from the token and converging Customer, Seller and Admin authorization.
- High priority
Socket.IO is single-instance and lacks connection authentication
Online customers, sellers and the admin are stored in process arrays and one admin variable, while connection events depend on client-provided IDs. There is no Redis adapter, acknowledgement, retry, offline queue or multi-instance broadcast path.
- Medium priority
Product filtering and dashboard analytics need a database path at scale
Public product filtering first loads all products and then performs category, price, rating, search, sorting and pagination in Node memory. Dashboard metrics also read broad order sets. Larger data should move into MongoDB queries, aggregations and indexes.
- Medium priority
Payments and production safeguards are not a complete loop yet
The Stripe code mainly creates a Seller Connect onboarding link; Checkout, Payment Intent and Webhook confirmation are not visible. The project also needs a fuller test suite, rate limiting, health checks, structured logs and CI/CD.
05 / NEXT ITERATION
What to improve next
- 01
Derive customer identity from authenticated tokens and complete server-side Customer, Seller and Admin RBAC
- 02
Recalculate totals and stock on the server, then protect checkout with MongoDB transactions, atomic updates and idempotency keys
- 03
Add JWT handshake auth, trusted origins, rooms, acknowledgements, reconnection and a Redis Socket.IO adapter
- 04
Move filters, pagination and dashboard metrics into MongoDB queries and aggregations with supporting indexes
- 05
Add Stripe Payment Intent and Webhook flows, order audit events, integration tests, health checks and structured observability