ShopWiz.mk — Multi-Vendor Marketplace
6/24/2026

Overview
ShopWiz.mk is a production multi‑vendor ecommerce marketplace built for the Macedonian market. Independent vendors apply, get approved, and run their own storefronts under one roof — managing products, orders, and payouts — while shoppers browse a unified catalog with search, faceted filters, comparison, wishlists, and a streamlined checkout. The entire experience is fully bilingual (English / Macedonian) with prices in Macedonian Denar (MKD).

Architecture
- Storefront (
client/): React 18 + Vite + Tailwind; Zustand for state, TanStack Query for data, react‑i18next for EN/MK localization, React Hook Form for forms - Admin (
admin/): a separate React + Vite SPA served onadmin.shopwiz.mkfor platform operators - API (
server/): Node + Express with MongoDB (Mongoose 8); JWT access/refresh auth plus Google OAuth, Sharp image processing, Redis caching, and hardened security middleware - Infra: Nginx reverse proxy across
shopwiz.mk,admin.shopwiz.mk, andapi.shopwiz.mk, with PM2 running the API in cluster mode
[client] → pages: Home, Products, Product, Categories, Category, Brands, Brand,
Vendors, Store, Cart, Compare, Checkout, Account, Wishlist
vendor portal: Dashboard, Products, Orders, Earnings, Customers, Reviews
[admin] → Dashboard, Vendors, Products, Orders, Categories, Brands, Coupons,
Shipping, Pages (CMS), Users, Settings
[server] → routes: products, categories, brands, vendors, cart, orders, coupons,
reviews, wishlist, payments(cPay), auth(JWT+OAuth), admin/*
models: User, Vendor, Product, Category, Brand, Order, OrderItem,
Coupon, Review, Wishlist, Invoice, Payout, ShippingClass
Storefront Features
- Catalog & discovery: hierarchical categories, brand pages, MongoDB text search, faceted listing with price / vendor / brand filters
- Product variants: variant combinations carry their own SKU, price, stock, and weight (not just price deltas) — accurate inventory at the combination level
- Cart & checkout: persistent cart (localStorage, synced on login), product comparison, guest checkout (email + token) alongside account checkout, separate shipping & billing addresses
- Engagement: wishlist with price‑drop alerts, reviews with verified‑purchase badges and threaded vendor↔customer conversations, loyalty tiers (Bronze→Platinum)


Brands & Categories
- Hierarchical categories with ancestor breadcrumbs, denormalized product counts, per‑category default sort, and dedicated icon / card / banner imagery
- Brand catalog with bilingual names and logos, browsable brand landing pages
- Both surfaces are bilingual (EN/MK) and feed the homepage merchandising


Vendor Portal
- Onboarding: vendor application → admin approval / rejection / blocking, store profile (logo, banner, hours, vacation mode, business & bank info)
- Per‑vendor order statuses: each vendor confirms, processes, and ships its portion of a shared order independently, with tracking numbers
- Flexible commission model: a vendor‑level default rate with per‑category overrides that cascade to subcategories
- Operations: earnings & payout history, customer lists, low‑stock alerts, review replies, and bulk Excel import with automatic EN→MK translation
Admin Console
- Dashboard: revenue, orders, AOV, new customers/vendors, refunds, completion rate, revenue‑over‑time, order/payment status, top products & vendors, catalog health, and recent orders
- Management: vendors & approvals, products & inventory, orders & refunds, hierarchical categories, brands
- Marketing & ops: a coupon engine with granular scoping (vendor / product / category / brand, usage limits), weight‑based shipping classes, CMS static pages, users & roles, and platform settings (cPay credentials, email, theme)

Advanced Implementation
Bilingual storefront & data layer
// client — react-i18next (EN/MK) + TanStack Query + Zustand
i18n.use(initReactI18next).init({ resources: { en, mk }, fallbackLng: 'mk' })
const { data } = useQuery(['products', filters], () => api.products.list(filters))
// product variant combinations: per-SKU price, stock, weight
{ attributes: { Color: 'Red', Size: 'M' }, sku: 'XXX-RED-M', price: 1490, stock: 12, weight: 0.4 }
Payments, security & jobs
// server — cPay card gateway with preauthorization (reserve, capture on ship)
app.use(helmet()); app.use(rateLimit({ windowMs: 60_000, max: 300 })); app.use(compression())
router.post('/payments/cpay/init', initPreauth) // → capture on fulfilment
// images: Sharp → WebP + thumbnails; emails: Resend + React Email; invoices: PDFKit
await sharp(buf).resize(1600).webp({ quality: 80 }).toFile(out)
Localization & SEO
- Full EN/MK localization via
client/src/locales, MKD currency formatting throughout - Per‑product SEO fields (title, description, slug) and bilingual category/brand metadata
- Transactional email automation (order, shipping, review, price‑drop) through Resend with React Email templates
What made it work
- A clean three‑app split — storefront, vendor portal, admin — over one well‑modeled API
- Marketplace primitives done properly: per‑vendor order lifecycles, cascading commissions, and combination‑level inventory
- Bilingual and payment‑local from day one (EN/MK + cPay + MKD), purpose‑built for the Macedonian market
Deliverables
- Customer storefront (browse, search, cart, guest & account checkout)
- Vendor portal (store profile, products, orders, payouts, reviews)
- Admin console (vendors, products, orders, coupons, categories, CMS, settings)
- cPay card payment integration with preauthorization
- Bilingual EN/MK experience (react‑i18next, MKD pricing)
- Bulk Excel product import with automatic translation