A productionβgrade, fullβstack eyewear commerce platform engineered for performance, security, and scale.
Live Site Β· Frontend Docs Β· Backend Docs Β· Shiprocket Architecture
- Overview
- Key Features
- Engineering Challenges & Solutions
- Technology Stack
- HighβLevel Design (HLD)
- LowβLevel Design (LLD)
- Frontend Architecture
- Backend Architecture
- Data Models
- API Surface
- Security Architecture
- ThirdβParty Integrations
- Project Structure
- Getting Started
- Environment Variables
- Deployment
- Contributing
- License
Voyar is a fullβfeatured, modern eβcommerce platform purposeβbuilt for premium eyewear retail. It pairs an Appleβinspired, motionβrich storefront with a hardened, OWASPβcompliant API server that handles the entire commerce lifecycle β from product discovery and virtual tryβon, through secure checkout and payment, to fulfillment, tracking, refunds, and postβpurchase support.
The platform is structured as a decoupled twoβtier monorepo:
| Tier | Stack | Purpose |
|---|---|---|
| Frontend | React 19 Β· TypeScript Β· Vite Β· Tailwind CSS Β· shadcn/ui Β· GSAP Β· Framer Motion Β· Lenis | Customer storefront, admin dashboard, immersive UX |
| Backend | Node.js Β· Express 5 (ESM) Β· MongoDB Β· Mongoose 9 Β· JWT Β· Razorpay Β· Shiprocket | RESTful API, auth, payments, order fulfillment, transactional email, webhook orchestration |
Design philosophy: Performanceβfirst, secureβbyβdefault, polished by motion β engineered with the rigor expected of a largeβcompany production system.
- Cinematic landing experience with GSAP ScrollTrigger, Framer Motion, and Lenis smooth scrolling
- Product catalog with color variants, multiβimage galleries, lens selectors, and bentoβgrid showcases
- Virtual tryβon module, mood/look curation, and "shop by gender" navigation
- Live shipment tracker and Razorpayβstyle payment timeline UI
- Customer reviews with verifiedβpurchase badges and helpful votes
- Light / dark theme toggle with persisted preference
- Fully responsive across mobile, tablet, and desktop
- JWTβbased authentication for both users and admins
- Email verification flow with oneβtime tokens
- TwoβFactor Authentication (2FA) via email OTP
- Secure password reset with cryptographic tokens
- OWASPβcompliant password strength validation
- Account lockout after 5 failed attempts
- Password history (prevents reuse of last 5 passwords)
- Multiple saved addresses, serverβsynced cart and wishlist
- Razorpay integration (live keys) with cryptographic signature verification
- Online payments + Cash on Delivery (COD) flows
- Webhookβdriven asynchronous payment event handling
- Full refund lifecycle (initiate β track β complete)
- Payment timeline modeled after Razorpay dashboard
- Timeβboxed payment tokens (30βminute expiry)
- Shiprocket API v2 integration for endβtoβend logistics
- Pincodeβbased courier serviceability check
- Automated AWB assignment, label & invoice generation
- Pickup location management (create, sync, select)
- Webhookβbased realβtime shipment status updates
- Bulk tracking and quickβship utilities
- Product CRUD with rich variant management
- Order pipeline (confirm β process β ship β deliver)
- User and admin management
- Site settings (singleton config)
- Analytics dashboards powered by Recharts
- Review moderation (approve / reject)
A nonβexhaustive look at the technical problems we solved and how.
| # | Challenge | Why it was hard | Solution |
|---|---|---|---|
| 1 | Buttery 60 fps storefront with heavy media | Hero animations, parallax, and scrollβlinked transitions are CPU/GPU heavy on midβtier devices. | GSAP ScrollTrigger + Framer Motion for GPUβaccelerated transforms, Lenis for inertia scrolling, codeβsplit routes via Vite, and lazyβloaded media in the BentoGrid and Hero components. |
| 2 | Atomic, raceβfree order placement | Concurrent buyers can race to claim the last unit of a SKU; a naive flow oversells stock. | Order creation runs inside a stockβdecrement guard in orderController using Mongoose conditional updates, so stock is reserved only on a successful, validated order β and reverted on payment failure or cancellation. |
| 3 | Verifiable online payments | Clientβside payment confirmations are forgeable; a malicious client could mark unpaid orders as paid. | Serverβside Razorpay signature verification in paymentController using HMACβSHA256 with the secret key, plus an idempotent webhook path that is the source of truth for terminal payment state. |
| 4 | Realβtime shipment tracking without polling | Polling Shiprocket per order does not scale and burns API quota. | Webhookβfirst architecture: Shiprocket pushes status updates to /api/shipping-webhook/webhook, validated via x-api-key, sanitized, and persisted to the order's tracking timeline (see SHIPROCKET_ARCHITECTURE.md). |
| 5 | OWASP Topβ10 hardening on a public API | Eβcommerce APIs are routinely scanned for injection, XSS, bruteβforce, and DoS. | Layered defense: Helmet headers, CORS allowβlist, expressβrateβlimit (perβroute tiers), expressβvalidator, xssβfilters, mongoβsanitize, 10 KB body cap, massβassignment protection via allowedFields. |
| 6 | Credentialβstuffing & bruteβforce on auth | Attackers automate login attempts against leaked credentials. | Account lockout after 5 failed logins, dedicated authLimiter rate limit, 2FA via email OTP, OWASP password strength rules, and password history to block reuse. |
| 7 | Reliable transactional email at scale | SMTP failures or template drift can silently break verification, OTP, and receipts. | Centralized Nodemailer transporter in config/email.js with reusable HTML templates for verification, OTP, password reset, order confirmation, and admin notifications. |
| 8 | Massβassignment via JSON bodies | Mongoose models with broad schemas allow privilege escalation through unexpected fields (role, isAdmin, wallet, etc.). |
A custom allowedFields middleware whitelists writable fields per route, stripping unknown keys before they reach controllers or models. |
| 9 | NoSQL injection through query operators | A $where, $ne, or nested operator in req.body can bypass auth or leak data. |
Global mongo-sanitize middleware and explicit query construction in controllers β never spreading raw client input into Mongoose queries. |
| 10 | Crossβorigin requests from multiple deployments | Storefront, admin, and webhook callers live on different origins (Vercel, custom domain, ngrok, Drive previews). | Allowβlistβdriven cors() configuration with origin callback, plus app.set("trust proxy", 1) for accurate client IPs behind Vercel. |
| 11 | Type safety across a large React 19 codebase | Untyped React components with rich domain data (orders, payments, shipments) drift quickly. | TypeScript strict mode via tsconfig.app.json, shared src/types/, ESLint with typescript-eslint, and react-hooks / react-refresh plugins. |
| 12 | Consistent design system with shadcn/ui + Tailwind | Adβhoc styling diverges across pages; pure utilities lose semantic meaning. | shadcn/ui primitives (Radix Slot/Icons, CVA variants) composed with clsx + tailwind-merge, themed via Tailwind config and CSS variables for light/dark. |
| 13 | Refunds and partial state | Refunds are inherently asynchronous and partial; UIs that only show "paid/refunded" hide reality. | A payment timeline model on Order records every state transition (authorized, captured, refund initiated, refund processed) and is rendered by the PaymentTimeline.tsx component. |
| 14 | Webhook reliability & idempotency | Both Razorpay and Shiprocket may retry deliveries; doubleβprocessing corrupts state. | Idempotent webhook handlers keyed on event/payment IDs, signature/x-api-key verification, and sanitized request logging that never echoes secrets. |
| 15 | Single source of truth for product variants | Eyewear has color variants Γ lens types Γ specs Γ multiple images β a flat schema explodes. | A nested Product schema with colorVariants[], perβvariant images, and specifications keeps queries simple while supporting rich rendering on the storefront. |
| Layer | Technology |
|---|---|
| Language | TypeScript 5.9 |
| Framework | React 19 |
| Build Tool | Vite 7 |
| Routing | React Router DOM 7 |
| Styling | Tailwind CSS 3.4, tailwindcss-animate, tailwind-merge, clsx |
| UI Primitives | shadcn/ui (Radix Slot, Radix Icons), class-variance-authority, Lucide React |
| Animation | GSAP (+ ScrollTrigger), Framer Motion, Lenis smooth scroll |
| Charts | Recharts |
| Linting | ESLint 9, typescript-eslint, eslint-plugin-react-hooks, eslint-plugin-react-refresh |
| Deployment | Vercel (vercel.json) |
| Layer | Technology |
|---|---|
| Runtime | Node.js 18+ (ES Modules) |
| Framework | Express.js v5 |
| Database | MongoDB Atlas with Mongoose 9 ODM |
| Authentication | jsonwebtoken, bcryptjs |
| Validation | expressβvalidator, validator.js |
| Security | helmet, cors, expressβrateβlimit, xssβfilters, mongoβsanitize |
| Payments | Razorpay SDK |
| Shipping | Shiprocket API v2 |
| Nodemailer (Gmail SMTP) | |
| Dev Tools | nodemon |
The platform is a classic threeβtier architecture (Client β API β Data) with two synchronous thirdβparty integrations (Razorpay, Shiprocket) and one asynchronous channel (SMTP), all glued together by a webhook bus for eventual consistency.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USERS β
β Customers (Web) Admins (Web) Couriers β
ββββββββββββ¬ββββββββββββββββββββ¬βββββββββββββββββββββ¬βββββββββ
β β β
βΌ βΌ β
ββββββββββββββββββββββββββββββββββββββββ β
β FRONTEND (Vercel Edge) β β
β React 19 Β· Vite Β· TS Β· Tailwind β β
β shadcn/ui Β· GSAP Β· Framer Β· Lenis β β
β Pages: Home, Collections, Product, β β
β Cart, Checkout, Orders, Profile, β β
β Admin Dashboard, Auth flows β β
βββββββββββββββββββββ¬βββββββββββββββββββ β
β HTTPS / JSON β
β JWT in Authorization header β
βΌ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β BACKEND API (Express 5) ββ
β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β β SECURITY EDGE β ββ
β β Helmet β CORS allowβlist β Body size cap β Trust Proxyβ ββ
β β β Sanitization (mongoβsanitize, xssβfilters) β ββ
β β β Rate limiters (standard / auth / payment / email) β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β β ROUTING LAYER β ββ
β β /api/products /api/orders /api/users /api/admin β ββ
β β /api/payment /api/reviews /api/shiprocket β ββ
β β /api/shipping-webhook β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β β CONTROLLER LAYER (business logic, orchestration) β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
β β MODEL LAYER (Mongoose schemas + validators) β ββ
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ ββ
ββββββββββ¬ββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬βββββββ
β β β β β
βΌ βΌ βΌ βΌ β
βββββββββββββββ ββββββββββββββ ββββββββββββββ βββββββββββββ
β MongoDB β β Razorpay β β Shiprocket β β Gmail ββ
β Atlas β β Gateway β β Logistics β β SMTP ββ
βββββββββββββββ βββββββ¬βββββββ βββββββ¬βββββββ βββββββββββββ
β β β
β webhooks β webhooks (status) β
ββββββββββ¬ββββββββ΄βββββββββββββββββββββ
βΌ
/api/...-webhook
(idempotent handlers)
- Browser loads the React bundle from Vercel's edge.
- User action (e.g., place order) triggers a fetch to the backend with the JWT in
Authorization: Bearer <token>. - Request passes through the security edge: Helmet headers β CORS check β sanitization β rate limiter.
- Router dispatches to the appropriate controller, which validates input and runs business logic.
- Mongoose models persist or read state from MongoDB Atlas.
- For payments: a Razorpay order is created serverβside; the client opens Razorpay Checkout; the server later verifies the signature and reconciles via webhook.
- For shipping: a Shiprocket shipment is created; status updates flow back via webhook rather than polling.
- Email sideβeffects (verification, OTP, receipts) are dispatched through Nodemailer.
- JSON response is returned to the React client; UI updates state and animates the transition.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β server.js β
β - dotenv.config() β
β - validateEnvironment() β
β - connectDB() β
β - app.use(helmet, cors, json, sanitizers, rateLimiters) β
β - app.use("/api/...", routeModules) β
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββΌββββββββββββββββββββββββββ
βΌ βΌ βΌ
ββββββββββββ βββββββββββββββ ββββββββββββββββ
β routes/ β β middleware/ β β config/ β
β *Routes βββusesββββΆβ auth.js β β db.js β
β β β validation β β email.js β
β β β rateLimiterβ β security.js β
ββββββ¬ββββββ βββββββββββββββ β shiprocket β
β ββββββββββββββββ
βΌ
ββββββββββββββββ βββββββββββββββ ββββββββββββββββββ
β controllers/ βββusesβΆβ models/ βββusesβΆβ MongoDB β
β *Controller β β Mongoose β β (Atlas) β
ββββββββ¬ββββββββ βββββββββββββββ ββββββββββββββββββ
β
ββββΆ Razorpay SDK βββΆ Razorpay API
ββββΆ shiprocket.js βββΆ Shiprocket REST
ββββΆ email.js (Nodemailer) βββΆ Gmail SMTP
User Frontend Backend Razorpay MongoDB Shiprocket
β β β β β β
β Checkout β β β β β
βββββββββββββΆβ β β β β
β β POST /api/orders β β β
β βββββββββββββββββΆβ β β β
β β β validate + reserve stock β β
β β ββββββββββββββββββββββββββββββββββΆβ β
β β β create Razorpay order β β
β β ββββββββββββββββββΆβ β
β β β { orderId } β β
β β βββββββββββββββββββ β
β β { rzpOrder } β β
β ββββββββββββββββββ β
β Razorpay Checkout opens β β
ββββββββββββββ β
β Pays β β
βββββββββββββΆβ β
β β POST /api/payment/verify (orderId, paymentId, signature) β
β βββββββββββββββββΆβ β
β β β HMAC verify signature β
β β β mark order PAID, push to timeline β
β β ββββββββββββββββββββββββββββββββββΆβ β
β β β create Shiprocket shipment β
β β βββββββββββββββββββββββββββββββββββββββββββββββββΆβ
β β β { awb, label, invoice } β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββ
β β { success } β β
β ββββββββββββββββββ β
β Order pageβ β
β β Email receipt sent via Nodemailer (async) β
β β β
β ... later ... β
β β ββββ Razorpay webhook (event) βββββ β
β β β reconcile / refund / capture β
β β ββββ Shiprocket webhook (status) βββββββββββββββββ
β β β append to order.tracking timeline β
Signup ββΆ POST /api/users/register
ββΆ bcrypt(password) β User created (isVerified=false)
ββΆ email verification token (signed JWT) β Nodemailer
Verify ββΆ GET /api/users/verify-email/:token β isVerified=true
Login ββΆ POST /api/users/login
ββΆ rate-limited (authLimiter)
ββΆ verify password (bcrypt.compare)
ββΆ if 2FA enabled β generate OTP β email β 200 { twoFactorRequired: true }
ββΆ else β sign JWT β 200 { token }
2FA OK ββΆ POST /api/users/verify-2fa { otp }
ββΆ verify OTP (time-window) β sign JWT β 200 { token }
Lockout ββΆ 5 failed attempts within window β account locked, alert email
Courier scan ββΆ Shiprocket Webhook Service
ββΆ POST https://api.voyareyewear.com/api/shipping-webhook/webhook
Headers: x-api-key, Content-Type: application/json
ββΆ express.json() β globalSanitizer β verify x-api-key
ββΆ shiprocketWebhookController.handleWebhook
β’ Find order by AWB / shipment_id
β’ Append { status, location, timestamp } to order.tracking
β’ Update top-level order.status when terminal
β’ Optionally email customer on key transitions
ββΆ 200 OK (idempotent β safe to retry)
<App>
βββ <ThemeProvider>
βββ <AuthProvider> (context/)
βββ <CartProvider>
βββ <BrowserRouter>
βββ <Navbar /> (scroll-aware, theme toggle)
βββ <Routes>
β βββ / β <Home>
β β βββ <Hero/> (GSAP timeline)
β β βββ <Features/>
β β βββ <BentoGrid/>
β β βββ <ShopByGender/>
β β βββ <ProductGrid/>
β β βββ <VirtualTryOn/>
β β βββ <MoodLook/>
β β βββ <BrandShowcase/>
β β βββ <Services/>
β β βββ <Testimonials/>
β β βββ <Newsletter/>
β β βββ <ContactCTA/>
β βββ /collections β <Collections>
β βββ /product/:id β <ProductDetail> (LensSelector, reviews)
β βββ /cart β <Cart>
β βββ /checkout β <Checkout> (Razorpay integration)
β βββ /orders β <Orders> (ShipmentTracker, PaymentTimeline)
β βββ /profile β <Profile> (TwoFactorAuth)
β βββ /login,/signup,/verify-email,/forgot,/reset
β βββ /admin/login,/admin/forgot,/admin/reset
β βββ /admin β <AdminDashboard> (Recharts analytics)
β βββ * β <NotFound>
βββ <Footer />
- Server state: fetched perβroute via typed
fetchwrappers insrc/config/, with JWT attached from auth context. - Auth state: held in a React Context (
src/context/) and persisted tolocalStorage; refreshed on app boot. - Cart state: optimistic local context, synced serverβside for loggedβin users so the cart survives device changes.
- Theme state: contextβdriven, with classβbased dark mode wired into Tailwind.
- Animations: GSAP timelines registered inside
useEffectwith cleanup; ScrollTrigger pinned/scrub configured per section; Lenis ties native scroll to GSAP'sticker.
| Choice | Rationale |
|---|---|
| Vite 7 | Subβsecond HMR, native ESM, fast TypeScript builds. Perfect for an animationβheavy SPA where iteration speed matters. |
| React 19 | Latest concurrent features, automatic batching, and improved Suspense unlock smoother route transitions. |
| TypeScript | Domain types (Product, Order, Payment, Shipment) are wide; compileβtime guarantees prevent prop drift across 17+ pages. |
| Tailwind + shadcn | Utilityβfirst speed without losing semantic components. shadcn primitives stay inβrepo, owned by us β no opaque vendor library. |
| GSAP + Framer | GSAP for complex, scrollβlinked timelines; Framer Motion for declarative microβinteractions on enter/exit and gestures. |
| Lenis | Smooths native scroll into a 60 fps inertia model that GSAP ScrollTrigger can drive deterministically. |
| Recharts | Composable, responsive admin charts without bringing in a heavy charting toolkit. |
| React Router 7 | Fileβagnostic routing with nested layouts and data APIs. |
- Tailwind config defines the palette, typography, container widths, and motion tokens.
- CSS variables drive light/dark theming so shadcn primitives respond automatically.
tailwind-merge+clsxare used everywhere class names are composed conditionally, preventing conflicting utilities from leaking through.class-variance-authoritypowers component variants (size, intent, tone) on shadcn buttons/cards.
- Routeβlevel code splitting via Vite's dynamic imports.
- Image optimization through
public/assets and<img loading="lazy">for belowβtheβfold media. - GSAP timelines created once per mount and killed on unmount to prevent memory leaks.
- Lenis tied into GSAP's ticker β single rAF loop instead of competing animation frames.
| Layer | Responsibility |
|---|---|
| server.js | Boot sequence: env validation β DB connect β security middleware β routes β start listener. |
| config/ | DB, email transporter, security helpers, Shiprocket client (with token caching). |
| middleware/ | auth.js (JWT verify + role guards), rateLimiter.js (perβtier limiters), validation.js (sanitizers). |
| routes/ | Thin routers binding HTTP verbs + paths to controllers, with perβroute validators and limiters. |
| controllers/ | All business logic. Pure async functions returning res.json(...) or throwing typed errors. |
| models/ | Mongoose schemas with validators, virtuals, hooks (e.g., bcrypt preβsave on User), and instance methods. |
| utils/ | Pure helpers (e.g., cryptographically secure OTP generator). |
- Environment validation at boot β the server refuses to start without required secrets (DB URI, JWT secret, Razorpay keys, SMTP credentials).
- Centralized error responses with sanitized messages (no stack traces leak in production).
- Sanitized request logging β never echo
Authorization,password, OTP, or webhook secrets into logs.
ββββββββββββ 1 βββββββββββ N ββββββββββββ
β User ββββββ Order ββββββ Item β (embedded snapshot of Product)
ββββββ¬ββββββ ββββββ¬βββββ βββββββ¬βββββ
β 1 β 1 β N
β N β 1 βΌ
ββββββΌββββββ ββββββΌβββββββββ ββββββββββββββ
β Address β β Payment β β Product β
β (embed) β β Timeline β βββββββ¬βββββββ
ββββββββββββ βββββββββββββββ β 1
βββββββββββββββ β N
β Shipment β ββββββΌββββββββββ
β Tracking β β ColorVariant β (embed)
βββββββββββββββ ββββββββββββββββ
ββββββββββββ N βββββββββββ
β User ββββββ Review βββNβββΆ Product
ββββββββββββ βββββββββββ
ββββββββββββ
β Admin β (separate collection; site-wide settings as singleton)
ββββββββββββ
| Model | Highlights |
|---|---|
| User | Email, hashed password (bcrypt), isVerified, twoFactorEnabled, passwordHistory[], failedLoginAttempts, addresses[], cart[], wishlist[]. |
| Product | Name, slug, description, brand, category, gender, price, MRP, stock, colorVariants[] (with images per color), specifications, ratings aggregate. |
| Order | Items snapshot, shipping address, payment block (provider, IDs, status), paymentTimeline[], shiprocket (shipmentId, awb, label, invoice), tracking[]. |
| Review | Product ref, user ref, rating, body, verifiedPurchase, helpfulVotes, status (pending/approved/rejected). |
| Admin | Email, hashed password, role, plus a singleton SiteSettings document for global config. |
See
backend/models/for the authoritative schema definitions.
All routes are namespaced under /api. Authentication uses Authorization: Bearer <jwt>.
| Group | Base path | Examples |
|---|---|---|
| Health | /api/health |
GET /api/health |
| Products | /api/products |
GET /, GET /:id, POST / (admin), PUT /:id (admin), DELETE /:id (admin), GET /search |
| Orders | /api/orders |
POST /, GET /my, GET /:id, PATCH /:id/status (admin) |
| Users / Auth | /api/users |
POST /register, POST /login, POST /verify-2fa, POST /forgot, POST /reset/:token, GET /me |
| Admin | /api/admin |
POST /login, GET /analytics, GET /users, siteβsettings endpoints |
| Payments | /api/payment |
POST /create, POST /verify, POST /cod, POST /refund, POST /webhook |
| Reviews | /api/reviews |
POST /, GET /product/:id, POST /:id/helpful, PATCH /:id/moderate (admin) |
| Shipping | /api/shiprocket |
Serviceability, create shipment, AWB, label, invoice, pickup locations, tracking |
| Shipping Webhook | /api/shipping-webhook |
POST /webhook (Shiprocket β Voyar) |
Full endpoint reference and payload contracts live in
backend/README.md.
A layered, defenseβinβdepth approach modeled on the OWASP Top 10.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β EDGE β
β β’ Helmet (HSTS, XβFrameβOptions, XβContentβTypeβOptionsβ¦) β
β β’ CORS allowβlist β
β β’ Trust proxy (correct client IPs behind Vercel) β
β β’ Body size cap (10 KB) β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SANITIZATION β
β β’ mongoβsanitize (strip $ / . operators) β
β β’ xssβfilters (escape user content) β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β RATE LIMITING (perβtier) β
β β’ standardLimiter (general API) β
β β’ authLimiter (login / register / 2FA) β
β β’ paymentLimiter (checkout / verify / refund) β
β β’ emailLimiter (resend verification / OTP) β
β β’ sensitiveLimiter (admin & destructive ops) β
β β’ publicLimiter (catalog browsing) β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AUTHN / AUTHZ β
β β’ JWT (signed, expiring) verified by middleware β
β β’ protect / protectOrAdmin / authMiddleware role guards β
β β’ Account lockout, password history, 2FA β
ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INPUT VALIDATION & MASSβASSIGNMENT GUARDS β
β β’ expressβvalidator schemas per route β
β β’ allowedFields whitelist before model writes β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Provider | Purpose | Touchpoints |
|---|---|---|
| MongoDB Atlas | Primary datastore | config/db.js connection, all Mongoose models |
| Razorpay | Payments + refunds + webhooks | controllers/paymentController.js, routes/paymentRoutes.js, frontend Checkout.tsx |
| Shiprocket | Shipping + tracking + webhooks | config/shiprocket.js, controllers/shiprocketController.js, controllers/shiprocketWebhookController.js, frontend ShipmentTracker.tsx, see SHIPROCKET_ARCHITECTURE.md |
| Gmail SMTP | Transactional email | config/email.js Nodemailer transporter and HTML templates |
| Vercel | Hosting (frontend + serverless) | frontend/vercel.json, frontend/.deployment, backend/.deployment |
Voyar/
βββ README.md β (this file)
βββ SHIPROCKET_ARCHITECTURE.md β Webhook architecture & sequence diagrams
βββ SHIPROCKET_QUICK_START.md
βββ SHIPROCKET_SETUP_FIX.md
βββ SHIPROCKET_WEBHOOK_SUMMARY.md
β
βββ backend/ β Node.js + Express 5 API server
β βββ server.js β App entrypoint
β βββ config/ β db, email, security, shiprocket
β βββ controllers/ β Business logic
β βββ middleware/ β auth, rateLimiter, validation
β βββ models/ β Mongoose schemas
β βββ routes/ β REST routers
β βββ utils/ β Helpers (OTP, etc.)
β βββ docs/ β Backend deepβdive docs
β βββ WEBHOOK_SETUP_GUIDE.md
β βββ WEBHOOK_SETUP_REQUIRED.md
β βββ README.md β Backend README
β βββ .env.example
β βββ package.json
β
βββ frontend/ β React 19 + Vite SPA
βββ index.html
βββ src/
β βββ main.tsx β React root
β βββ App.tsx β Router + providers
β βββ components/ β UI building blocks (shadcn + custom)
β β βββ ui/ β shadcn/ui primitives
β βββ pages/ β Route components
β βββ context/ β Auth / cart / theme contexts
β βββ config/ β API client + env config
β βββ data/ β Static seed/demo data
β βββ lib/ β cn(), helpers
β βββ styles/ β Global styles
β βββ types/ β Shared TS types
β βββ assets/
βββ public/
βββ docs/
βββ tailwind.config.js
βββ vite.config.ts
βββ tsconfig*.json
βββ eslint.config.js
βββ vercel.json
βββ README.md β Frontend README
βββ .env.example
βββ package.json
- Node.js v18+
- npm v9+
- MongoDB Atlas cluster (or local MongoDB)
- Razorpay account (live or test keys)
- Shiprocket account (API user + password)
- Gmail account with an App Password (for SMTP)
git clone https://github.com/Sayan-dev731/Voyar.git
cd Voyarcd backend
cp .env.example .env # then fill in values (see next section)
npm install
npm run dev # http://localhost:5000In a new terminal:
cd frontend
cp .env.example .env # set VITE_API_BASE_URL to your backend
npm install
npm run dev # http://localhost:5173# Backend
cd backend && npm start
# Frontend
cd frontend && npm run build && npm run previewNever commit real secrets. Use
.env.examplefiles as a template.
| Variable | Purpose |
|---|---|
PORT |
API port (default 5000) |
NODE_ENV |
development | production |
MONGO_URI |
MongoDB Atlas connection string |
JWT_SECRET |
Secret for signing user/admin JWTs |
JWT_EXPIRES_IN |
e.g. 7d |
RAZORPAY_KEY_ID |
Razorpay key ID |
RAZORPAY_KEY_SECRET |
Razorpay key secret |
RAZORPAY_WEBHOOK_SECRET |
Secret to verify Razorpay webhook signatures |
SHIPROCKET_EMAIL |
Shiprocket API user |
SHIPROCKET_PASSWORD |
Shiprocket API password |
SHIPROCKET_WEBHOOK_TOKEN |
x-api-key for Shiprocket β Voyar webhooks |
SMTP_HOST / SMTP_PORT |
Gmail SMTP host & port |
SMTP_USER / SMTP_PASS |
SMTP credentials (use Gmail App Password) |
EMAIL_FROM |
Sender address shown to users |
FRONTEND_URL |
Public URL of the frontend (used in email links) |
| Variable | Purpose |
|---|---|
VITE_API_BASE_URL |
Backend base URL, e.g. http://localhost:5000/api |
VITE_RAZORPAY_KEY_ID |
Public Razorpay key ID for the Checkout widget |
| Component | Target | Notes |
|---|---|---|
| Frontend | Vercel (frontend/vercel.json) |
Static SPA build (vite build), edgeβcached, custom domain voyareyewear.com. |
| Backend | Vercel Serverless / Node host | app.set("trust proxy", 1) is enabled for accurate client IPs behind reverse proxies. |
| Database | MongoDB Atlas | Configure IP allowβlist and a leastβprivilege DB user. |
| Webhooks | Razorpay & Shiprocket dashboards | Point to /api/payment/webhook and /api/shipping-webhook/webhook respectively. |
See SHIPROCKET_QUICK_START.md and backend/WEBHOOK_SETUP_GUIDE.md for webhook setup.
Contributions, issues, and feature requests are welcome.
- Fork the repository.
- Create a feature branch:
git checkout -b feat/awesome-thing. - Commit using clear messages:
git commit -m "feat(orders): add bulk export". - Run linters and basic smoke tests:
cd frontend && npm run lint && npm run build cd backend && npm run dev # smoke test
- Push and open a Pull Request against
main.
Please follow existing patterns:
- Keep controllers thin; move shared logic to
utils/orconfig/. - Add new routes behind the appropriate rate limiter and validator.
- Use typed props and shadcn primitives for new React components.
- Never log secrets, OTPs, JWTs, or webhook payloads verbatim.
This project is licensed under the ISC License. See individual package.json files for details.
Built with care by the Voyar engineering team.
Live Site Β· Frontend README Β· Backend README Β· Shiprocket Architecture