A full-stack, production-grade platform that lets customers discover, book, and pay for professional beauty and salon services delivered to their doorstep — backed by a complete admin suite for managing services, bookings, slots, payments, and customers.
🌐 Live: wemakeover.co.in
- Overview
- Key Features
- Tech Stack
- System Architecture
- Repository Structure
- Getting Started
- Environment Variables
- Available Scripts
- API Surface
- Core Domain Concepts
- Security
- Deployment
- Roadmap
- License
WeMakeover is a MERN-based marketplace for at-home beauty and salon services across serviceable cities in India. Customers browse curated services across categories (with tiered offerings — Regular, Classic, Premium, Bridal), add them to a cart, pick an available appointment slot, and pay securely online. Behind the scenes, a feature-rich admin dashboard gives the business full control over the catalog, availability, bookings, payments, reviews, customers, and site-wide settings.
The codebase is organized as a monorepo with two independently deployable applications:
| App | Path | Description |
|---|---|---|
| Client | /client |
React + Vite single-page application (customer & admin UI) |
| Server | /server |
Express REST API with MongoDB, Redis, and background jobs |
- Service discovery — browse services by category with tiered service types (Regular → Classic → Premium → Bridal).
- Smart cart — persistent cart with auto-save (Redux Persist + debounced server sync).
- Serviceability check — verify whether a city is serviceable before booking; request a new city if not covered.
- Slot booking — real-time appointment slots generated from configurable working days and booking rules.
- Secure checkout — online payments via Razorpay with signature verification and webhooks.
- Address book — manage multiple delivery/service addresses.
- Bookings & history — track current and past bookings with detailed status.
- Reviews — submit and view service reviews via secure, token-based review links.
- Newsletter & enquiries — subscribe to updates and reach out through contact forms.
- Notifications — in-app notifications for booking and account events.
- Email/password signup with email verification (OTP) and password reset flows.
- Google OAuth sign-in.
- JWT-based sessions using access + refresh tokens stored in secure HTTP-only cookies.
- Dashboard with business metrics and insights.
- Catalog management — create/update categories and services with image uploads.
- Bookings & customers management with detailed views.
- Slot & availability control — working days, daily slots, and automated slot generation.
- Serviceable cities management and city-request triage.
- Reviews moderation.
- Enquiries inbox.
- Site settings management.
- Admin team management with secure, token-based admin onboarding and account activation/deactivation.
| Concern | Technology |
|---|---|
| Framework | React 18 |
| Build tool | Vite 5 |
| State management | Redux Toolkit + React-Redux + Redux Persist |
| Routing | React Router DOM 7 (lazy-loaded, code-split routes) |
| Styling | Tailwind CSS 3, PostCSS, Autoprefixer |
| Animation / UX | Framer Motion, Lenis (smooth scroll), Lottie |
| HTTP | Axios (with interceptors) |
| Auth | @react-oauth/google |
| Payments | Razorpay Checkout |
| Notifications | React Hot Toast |
| Icons | Lucide React, React Icons |
| Concern | Technology |
|---|---|
| Runtime | Node.js (ES Modules) |
| Framework | Express 5 |
| Database | MongoDB via Mongoose 8 |
| Caching / sessions | Redis (ioredis) |
| Auth | JWT (jsonwebtoken), bcryptjs, Google Auth Library |
| Payments | Razorpay |
| Nodemailer | |
| OTP | otp-generator |
| File uploads | express-fileupload + Cloudinary / AWS S3 (pluggable factory) |
| Scheduling | node-cron (slot generation jobs) |
| Security | Helmet, CORS allowlist, cookie-parser |
┌──────────────────────────────┐
│ Browser │
│ React SPA (Vite build) │
│ Redux store + Persist │
└───────────────┬──────────────┘
│ HTTPS (Axios, cookies)
▼
┌──────────────────────────────┐
│ Express REST API │
│ Helmet · CORS · ReqContext │
│ ReadinessGate · ErrorHandler │
└───┬───────┬───────┬───────┬───┘
│ │ │ │
┌─────────────┘ │ │ └──────────────┐
▼ ▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────────┐
│ MongoDB │ │ Redis │ │ Razorpay │ │ Cloudinary │
│ (Mongoose) │ │ (ioredis) │ │ Payments │ │ / AWS S3 │
└────────────┘ └────────────┘ └────────────┘ └──────────────┘
▲
┌────────┴─────────┐
│ node-cron jobs │
│ (slot generation) │
└───────────────────┘
Request lifecycle highlights
- A request-context middleware attaches a correlation
requestIdand scoped logger to every request. - A readiness gate ensures
/apiroutes only serve traffic once the database connection is ready (health endpoints stay open). - A centralized error handler normalizes all error responses (including 404s) and preserves CORS headers on failures.
- Image uploads route through an Upload Factory that selects Cloudinary or AWS S3 based on
IMAGE_UPLOAD_PROVIDER, so the storage backend can be swapped without code changes.
wemakeover-aws/
├── client/ # React + Vite frontend
│ ├── src/
│ │ ├── assets/ # Images, icons, lottie, fonts
│ │ ├── components/ # UI: admin, booking, common, layout, modals, ui
│ │ ├── features/ # Redux slices + API per domain (auth, cart, booking, …)
│ │ ├── hooks/ # Reusable hooks (e.g. useCartAutoSave)
│ │ ├── pages/ # Route-level pages (home, auth, admin, reviews, …)
│ │ ├── provider/ # LenisProvider, ScrollToTop
│ │ ├── routes/ # Router + route guards (Protected/Auth/Admin)
│ │ ├── stores/ # Redux store + persist config
│ │ ├── utils/ # Client utilities
│ │ ├── App.jsx
│ │ └── main.jsx
│ ├── index.html
│ ├── vite.config.js
│ └── tailwind.config.js
│
└── server/ # Express REST API
└── src/
├── configs/ # mongodb, redis, cloudinary, s3, nodemailer
├── config/ # central env validation
├── controllers/ # Route handlers (+ admin/)
├── routes/ # Express routers (+ admin/)
├── services/ # Business logic (auth, booking, payment, upload, …)
├── models/ # Mongoose schemas
├── middlewares/ # auth, errorHandler, readinessGate, requestContext, …
├── jobs/ # node-cron slot generation
├── platform/ # db + logging platform code
├── utils/ # tokens, payments, validation helpers
├── scripts/ # seed scripts (e.g. serviceable cities)
└── server.js # App entry point
Domain features on the client are colocated under
features/<domain>/— each typically pairs a Redux slice with its API module, keeping state and data-access logic together.
- Node.js 18+ and npm
- MongoDB (local or Atlas)
- Redis instance (local or hosted)
- A Cloudinary account (default) or AWS S3 bucket for image uploads
- A Razorpay account (key id/secret) for payments
- A Google OAuth client ID for social login
- An SMTP/email account for Nodemailer
git clone <your-repo-url>
cd wemakeover-awscd server
npm install
# Create a .env file (see Environment Variables below)
npm run dev # starts API on http://localhost:3000 with nodemoncd client
npm install
# Create a .env file (see Environment Variables below)
npm run dev # starts Vite dev server (default http://localhost:5173)Open the app in your browser and you're ready to go. 🎉
Create a .env file in each app directory. Below are the variables referenced throughout the codebase.
# Core
NODE_ENV=development
PORT=3000
MONGODB_URI=mongodb://localhost:27017/wemakeover
CLIENT_URL=http://localhost:5173
FRONTEND_URL=http://localhost:5173
BACKEND_URL=http://localhost:3000
# Auth (JWT)
JWT_SECRET=your_jwt_secret
JWT_ACCESS_SECRET=your_access_secret
JWT_REFRESH_SECRET=your_refresh_secret
# Redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
# Email (Nodemailer)
EMAIL_SERVICE=gmail
EMAIL_USER=your@email.com
EMAIL_PASSWORD=your_app_password
ADMIN_EMAIL=hello@wemakeover.co.in
ADMIN_PHONE_NUMBER=+91XXXXXXXXXX
# Payments (Razorpay)
RAZORPAY_KEY_ID=your_key_id
RAZORPAY_KEY_SECRET=your_key_secret
RAZORPAY_WEBHOOK_SECRET=your_webhook_secret
# Image upload provider: "cloudinary" (default) or "s3"
IMAGE_UPLOAD_PROVIDER=cloudinary
MAX_FILE_SIZE=26214400 # 25 MB in bytes
# Cloudinary
CLOUDINARY_CLOUD_NAME=your_cloud_name
CLOUDINARY_API_KEY=your_api_key
CLOUDINARY_API_SECRET=your_api_secret
# AWS S3 (required only if IMAGE_UPLOAD_PROVIDER=s3)
AWS_REGION=ap-south-1
AWS_ACCESS_KEY_ID=your_access_key
AWS_SECRET_ACCESS_KEY=your_secret_key
AWS_S3_BUCKET_NAME=your_bucketVITE_BACKEND_URL=http://localhost:3000/api
VITE_RAZORPAY_KEY_ID=your_razorpay_key_id
VITE_GOOGLE_CLIENT_ID=your_google_oauth_client_id
⚠️ Never commit.envfiles. OnlyMONGODB_URIis strictly required at server startup; missing optional integrations degrade gracefully where possible (e.g., the API continues to run with limited functionality if Redis is unavailable).
| Script | Description |
|---|---|
npm run dev |
Start the Vite dev server with HMR |
npm run build |
Production build (drops console/debugger) |
npm run preview |
Preview the production build locally |
npm run lint |
Run ESLint across the project |
| Script | Description |
|---|---|
npm run dev |
Start the API with nodemon (auto-reload) |
npm start |
Start the API for production |
The API is mounted under the /api prefix. Health endpoints are always available; all other routes wait for database readiness.
| Area | Base Route |
|---|---|
| Health | /api/health |
| Auth | /api/auth |
| Services | /api/services |
| Categories | /api/categories |
| Cart | /api/cart |
| Addresses | /api/addresses |
| Bookings | /api/bookings |
| Working Days | /api/working-days |
| Daily Slots | /api/daily-slots |
| Slot Automation | /api/slot-automation |
| Payments | /api/payment |
| Reviews | /api/reviews |
| Newsletter | /api/newsletter |
| Enquiry / Contact | /api/enquiry, /api/ |
| Notifications | /api/notifications |
| Serviceability | /api/city-requests, /api/site-settings |
| Admin | /api/admin/* (dashboard, bookings, customers, enquiries, categories, services, reviews, admins, serviceable-cities, city-requests, booking-config, site-settings, upload, onboard) |
- Service Types — every service can offer multiple tiers, displayed in the order Regular → Classic → Premium → Bridal.
- Serviceable Cities — bookings are gated by city coverage; users in uncovered areas can submit a city request that admins triage.
- Working Days & Daily Slots — admins define working days and booking configuration; a node-cron job automatically generates upcoming daily slots so customers always see fresh availability.
- Bookings & Payments — a booking is paired with a Razorpay order; payment signatures and webhooks are verified server-side before confirmation, and confirmation emails are dispatched to customer and admin.
- Pluggable Uploads — image storage is abstracted behind an
UploadFactory, switchable between Cloudinary and AWS S3 via a single env var. - Token-based Flows — secure tokens power email verification, password reset, review submission links, and admin onboarding.
- Helmet sets secure HTTP headers;
x-powered-byis disabled. - CORS allowlist restricts origins, with credentials enabled for cookie-based auth.
- JWT access/refresh tokens stored in HTTP-only cookies with environment-aware flags.
- Password hashing with bcrypt and
passwordChangedAttracking to invalidate stale tokens. - Server-side payment verification (HMAC signature + webhook secret) before fulfilling orders.
- Upload validation with strict file size/type limits (25 MB max).
- Centralized error handling that avoids leaking internal details in production.
- Frontend builds to static assets (
npm run build) and can be hosted on any static/CDN host (e.g., Netlify, Vercel, S3 + CloudFront). PointVITE_BACKEND_URLat the deployed API. - Backend runs as a long-lived Node process (
npm start). Provision MongoDB, Redis, and the chosen image provider, then set all server environment variables. The CORS allowlist (CLIENT_URL+ production domains) must include the deployed frontend origin. - The repository name reflects an AWS-oriented deployment, with native support for AWS S3 image storage via the upload factory.
Potential enhancements (not exhaustive):
- Automated test suite (unit + integration) for client and server.
- OpenAPI/Swagger documentation for the REST API.
- CI/CD pipeline and containerized (Docker) deployments.
- TypeScript migration for end-to-end type safety.
This project is provided under the ISC License (see the server package manifest). All third-party trademarks and brand assets belong to their respective owners.
Made with care for effortless beauty bookings — WeMakeover 💖