Shreephal Handicrafts — E-Commerce Platform
Full-stack e-commerce platform for a Jabalpur-based handicraft and trophy store — featuring product customization uploads, Razorpay payment integration, admin dashboard, PDF invoice generation, and a PWA-ready architecture built entirely on Supabase as the backend.
Problem Statement
Shreephal Handicrafts was operating without any online presence, relying on word-of-mouth and offline orders. Customers had no way to browse products, place customized orders (e.g., engraved trophies, personalized gifts), make payments digitally, or track their orders. The business also had no internal tools to manage inventory, review customization requests, or generate invoices — all of which were done manually.
Solution
Built a production-grade full-stack e-commerce platform from scratch using React 18 + Vite on the frontend and Supabase (PostgreSQL) as a backend-as-a-service. The platform supports the complete shopping lifecycle — product browsing with filters, product customization via image/file uploads, cart management, checkout with live stock reservation, Razorpay payment gateway, order tracking, and PDF invoice download. An admin dashboard was built in parallel for the business owner to manage products, categories, orders, and review customer customization submissions — requiring zero technical knowledge.
Code Structure
shreephal-handicrafts/
├── frontend/
│ ├── src/
│ │ ├── pages/ # 20+ route-level pages
│ │ │ ├── admin/ # Admin-only pages (protected)
│ │ │ └── *.jsx # Public + user pages
│ │ ├── components/ # 40+ reusable components
│ │ │ ├── admin/ # Admin-specific components
│ │ │ ├── CheckOut/ # Checkout flow components
│ │ │ ├── hero/ # Homepage hero components
│ │ │ ├── product/ # Product detail sub-components
│ │ │ ├── SEO/ # SEO meta components
│ │ │ └── ui/ # Radix-based shadcn primitives
│ │ ├── contexts/ # React Context providers
│ │ │ ├── AuthContext.jsx
│ │ │ ├── CartContext.jsx
│ │ │ ├── FavouritesContext.jsx
│ │ │ └── RouteGuards.jsx
│ │ ├── hooks/ # Custom React hooks
│ │ │ ├── useStockReservation.js
│ │ │ ├── usePagination.js
│ │ │ └── useBreadcrumbs.js
│ │ └── services/
│ │ └── orderService.js
│ └── package.json
├── api/
│ └── payments/ # Serverless payment functions
├── supabase/
│ ├── functions/ # PostgreSQL stored functions
│ └── migrations/ # Versioned DB migrations
└── docs/ # Architecture + integration docs
Key Strategies
BaaS-first architecture
Used Supabase as the entire backend — eliminating the need to build and deploy a separate API server, reducing infrastructure cost to near-zero for a small business client
Order snapshot pattern
Implemented PostgreSQL snapshot tables to freeze product price, name, and image at the moment of purchase — ensuring billing accuracy regardless of future product edits
Concurrent stock reservation
Built a PostgreSQL stored function + React hook to temporarily reserve stock during checkout, preventing overselling in concurrent user scenarios
Dual payment gateway
Integrated Razorpay as primary (UPI, cards, net banking, wallets) with PhonePe tested in sandbox — giving the business flexibility to switch without a full rewrite
Admin-first design
Built the admin panel before most customer-facing features — ensuring the business owner can populate and manage content independently before launch
Technical Challenges
Performance Decisions
PWA enabled via vite-plugin-pwa — app is installable on mobile with offline support
Lazy loading images via custom OptimizedImage.jsx component with fallback states
React Query handles server state caching, deduplication, and background refetch — avoiding redundant API calls to Supabase
Vite 5 build tooling with tree-shaking, code-splitting, and ~< 2s dev server start
Offline detection via OfflineDetector.jsx — graceful degradation when network drops
Invoice generation (jsPDF + html2canvas) runs client-side — zero server load for PDF exports
Local SEO landing page (TrophyShopJabalpur.jsx) targeting "trophy shop Jabalpur" search intent
Lessons Learned
Snapshot pattern is non-negotiable for e-commerce: Learned mid-development that if product prices change after an order is placed, the order history breaks. Implemented an order-snapshot + billing-snapshot pattern using PostgreSQL migrations — all order data is frozen at checkout time. This required 5 separate migrations to get right.
Stock reservation is harder than it looks: Implemented a useStockReservation.js hook (11KB) and 01_stock_management.sql PostgreSQL function to create temporary holds during checkout — otherwise concurrent users can both "buy" the last item.
Payment webhook verification is critical: Initially planned to trust frontend payment callbacks, but implemented proper HMAC signature verification on the server (razorpay-verify.js) to prevent spoofed payment confirmations.
Admin UX matters as much as user UX: The business owner (non-technical) needed to manage products, categories, and orders without developer help — spent significant time on the admin dashboard UI to make it intuitive.
PWA offline states need explicit UI: Simply adding vite-plugin-pwa isn't enough — built an OfflineDetector.jsx component to show users a clear offline banner rather than silent failures.
Future Improvements
Email notifications: Transactional emails (order confirmation, shipping updates) via Resend or Supabase Edge Functions
Analytics dashboard: Sales reports, product performance, and revenue charts for the business owner
WhatsApp integration: Auto-send order details to customer and business via WhatsApp Business API (critical for Indian SMB market)
COD (Cash on Delivery): High demand feature for Tier-2/3 Indian markets where UPI/card adoption is lower
Multi-language support (Hindi): Large chunk of customers are Hindi-speaking — i18n with react-i18next
Shiprocket/Delhivery integration: Automated shipping label generation and tracking updates
Security Considerations
Supabase Row Level Security (RLS): Every table has RLS policies — users can only read/write their own orders; admin operations use the service role key server-side only
Razorpay signature verification: All payment completions are server-verified using HMAC-SHA256 before order status is updated in the DB — frontend cannot spoof a successful payment
Razorpay webhook endpoint (webhook.js) validates X-Razorpay-Signature header on every event
Private routes: PrivateRoute.jsx + RouteGuards.jsx protect all user and admin pages — unauthenticated access redirects to login
Environment variables: All API keys (Razorpay key/secret, Supabase service key) are server-side only — never exposed to the browser bundle
Password recovery guard: PasswordRecoveryGuard.jsx ensures the reset password page is only accessible via a valid Supabase recovery token link
Explore Shreephal Handicrafts — E-Commerce Platform
Check out the source code or see it live.
