A full-stack storefront for handmade crochet and yarn creations.
CraftyWrap lets customers browse handcrafted products, build a cart, place an order, request a custom design, and manage their account. Store administrators have a protected dashboard for managing catalogue data, promotions, orders, reviews, and users.
- Responsive product catalogue with filtering, search, sorting, product details, related products, reviews, and wishlists.
- Persistent guest and signed-in carts, including guest-cart merging after authentication.
- Account registration, JWT sign-in, a Google ID-token authentication endpoint, saved addresses, and order history.
- Checkout for guests and customers, promo-code validation, gift wrapping, UPI/manual payment, and Razorpay payment verification.
- Custom-order requests with optional JPEG, PNG, or WebP reference images stored in Cloudinary.
- Role-based administration for products, themes, product types, promotional codes, orders, reviews, custom orders, and users.
- Automatic initial catalogue seeding when the connected database has no products.
| Layer | Technology |
|---|---|
| Client | Next.js 14, React 18, TypeScript, Tailwind CSS, Framer Motion |
| Server | Express 5, TypeScript, Mongoose |
| Database | MongoDB |
| Authentication | JWT, bcrypt, Google Identity token verification |
| Payments | Razorpay |
| Media uploads | Multer (memory storage) and Cloudinary |
CraftyWrap/
├── frontend/ # Next.js storefront and admin interface
│ ├── src/app/ # Routes: home, collections, cart, checkout, account, admin
│ ├── src/components/ # Reusable UI, loading states, and animations
│ ├── src/context/ # Cart and authenticated-user state
│ └── .env.example # Public client configuration template
└── backend/ # Express API
├── src/controllers/ # Request handlers and validation schemas
├── src/models/ # Mongoose documents
├── src/routes/ # API route definitions
├── src/services/ # Cart, order, and promotion business logic
├── src/seed/ # Upsert-based catalogue seed data
└── .env.example # Server configuration template
- Node.js 20 LTS or newer
- npm 9 or newer
- A MongoDB database (Atlas or local)
Optional integrations:
- Razorpay API keys for online card/UPI payment collection
- Google OAuth client ID for Google ID-token authentication
- Cloudinary credentials for custom-order and review image uploads
-
Install dependencies from the repository root:
npm --prefix backend install npm --prefix frontend install
-
Create local environment files:
Copy-Item backend/.env.example backend/.env Copy-Item frontend/.env.example frontend/.env.local
-
Set
MONGODB_URIand a long, uniqueJWT_SECRETinbackend/.env. Add the optional provider credentials if those integrations will be used. -
Start the API in one terminal:
cd backend npm run dev
-
Start the storefront in another terminal:
cd frontend npm run dev
Open http://localhost:3000. The API health endpoint is available at http://localhost:5000/health.
On its first successful database connection, the backend adds the sample product types, themes, products, and the CRAFTY10 promo code if the product collection is empty. To apply the supplied seed values again, run:
cd backend
npm run seedThe seed process upserts its named product types, design themes, products, and default promo code; do not use it if you do not want those records refreshed to the supplied values.
| Variable | Required | Description |
|---|---|---|
MONGODB_URI |
Yes | MongoDB connection string. |
JWT_SECRET |
Yes | Long random secret used to sign access tokens. |
FRONTEND_ORIGIN |
Yes | Allowed client origin(s), comma-separated. Defaults to http://localhost:3000. |
PORT |
No | API port. Defaults to 5000. |
GOOGLE_CLIENT_ID |
For Google authentication | OAuth web client ID used to verify Google ID tokens. |
RAZORPAY_KEY_ID |
For Razorpay | Razorpay key ID used to create payment orders. |
RAZORPAY_KEY_SECRET |
For Razorpay | Razorpay secret used to create and verify payment orders. |
CLOUDINARY_CLOUD_NAME |
For image uploads | Cloudinary cloud name. |
CLOUDINARY_API_KEY |
For image uploads | Cloudinary API key. |
CLOUDINARY_API_SECRET |
For image uploads | Cloudinary API secret. |
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_API_URL |
Yes | API base URL, normally http://localhost:5000/api. |
NEXT_PUBLIC_GOOGLE_CLIENT_ID |
For a Google sign-in UI | Same Google web client ID used by the API. |
NEXT_PUBLIC_RAZORPAY_KEY_ID |
For Razorpay checkout | Public Razorpay key ID. Never place the Razorpay secret here. |
NEXT_PUBLIC_* values are bundled into the browser. Keep all secrets—including JWT_SECRET, Razorpay secret, and Cloudinary secret—only in backend/.env.
Google authentication note: The API can verify a Google ID token at
POST /api/auth/google, but the current storefront does not initialize the Google Identity library or obtain that token itself. Add that client integration before presenting Google sign-in as a working customer flow.
| Route | Purpose |
|---|---|
/ |
Landing page with featured products and themes. |
/collections |
Searchable and filterable catalogue. |
/products/[id] |
Product details, related items, and reviews. |
/cart |
Shopping cart, gift options, and promotion codes. |
/checkout |
Shipping details and payment flow. |
/custom-order |
Custom handmade-item request form. |
/login and /signup |
Customer authentication. |
/account |
Profile, addresses, wishlist, order history, and custom-order history. |
/admin |
Protected store management dashboard for administrators. |
All API endpoints are rooted at /api and return the following envelope:
{
"success": true,
"message": "Human-readable result",
"data": {}
}Protected endpoints use a bearer token:
Authorization: Bearer <access-token>Guest cart and checkout calls identify a browser cart with:
X-Cart-Token: <client-generated-token>| Resource | Main endpoints |
|---|---|
| Authentication | POST /auth/register, POST /auth/login, POST /auth/google |
| User account | GET/PATCH /users/me, GET/PUT /users/me/wishlist/:productId, GET /users/me/wishlist |
| Products | GET/POST /products, GET /products/autocomplete, GET /products/:slug, GET /products/:slug/related, PATCH/DELETE /products/:productId |
| Product metadata | GET/POST /product-types, GET/POST /design-themes plus admin PATCH/DELETE operations |
| Cart | GET /carts/current, POST /carts/items, PATCH/DELETE /carts/items/:productId, PATCH/DELETE /carts/current, POST /carts/merge |
| Orders | POST /orders/checkout, POST /orders/:orderId/verify-payment, GET /orders/me, admin GET/PATCH /orders |
| Custom orders | POST /custom-orders, GET /custom-orders/me, and admin list/update operations |
| Reviews | GET /reviews/product/:slug, POST /reviews/product/:slug, plus admin list/update/delete operations |
| Promotions | POST /promo-codes/validate, plus admin CRUD endpoints |
| Newsletter | POST /newsletter |
The admin operations require a token belonging to a user whose role is admin. New registrations are created as customer users; an existing admin can promote a user from the Users section of /admin.
Checkout supports razorpay and upi_manual payment methods. When valid Razorpay server credentials are configured, Razorpay orders are created and payment signatures are verified by the API. Without those credentials, use upi_manual for a local/demo flow; Razorpay verification will not be available.
Custom-order reference images and review images are limited to JPEG, PNG, or WebP files up to 10 MB. Uploading an image requires valid Cloudinary server credentials.
Build each service independently:
cd backend
npm run build
npm startcd frontend
npm run build
npm startBefore deployment, update FRONTEND_ORIGIN and NEXT_PUBLIC_API_URL to the production URLs, configure the same Google client ID on both services, and add the production Razorpay and Cloudinary credentials as needed.
- CORS permits only the origins listed in
FRONTEND_ORIGIN(or requests without anOriginheader). - Access tokens and guest cart tokens are stored in browser local storage by the storefront.
- Product deletion is implemented as deactivation, which preserves order references while removing the item from the active catalogue.
- The MongoDB connection must support transactions for checkout stock updates; use a replica set deployment such as MongoDB Atlas.
| Directory | Command | Description |
|---|---|---|
frontend |
npm run dev |
Start the Next.js development server. |
frontend |
npm run build |
Create a production client build. |
frontend |
npm start |
Serve the built client. |
frontend |
npm run lint |
Run the configured Next.js lint command. |
backend |
npm run dev |
Start the API with automatic TypeScript reloads. |
backend |
npm run build |
Compile TypeScript to dist/. |
backend |
npm start |
Run the compiled API. |
backend |
npm run seed |
Upsert the supplied catalogue data. |
- Do not commit
.env,.env.local, provider secrets, or production database URLs. - Use a unique, high-entropy
JWT_SECRETfor every deployed environment. - Restrict Google OAuth, Razorpay, Cloudinary, MongoDB, and CORS settings to the deployed domains and least required permissions.
- Enable TLS for the frontend, API, and database connections in production.
