Paushtik Farms - Ghee eCommerce Platform
End-to-end eCommerce platform for a premium ghee brand - clean storefront, integrated payment gateway, inventory management, and shipment handling, deployed for scale.
The challenge
Ship a D2C platform that orchestrates the complete order flow - storefront → cart → payment → inventory → shipping - while staying resilient to the real-world failures that hit live commerce: webhooks arriving out of order, payment captures racing with client-side verifies, and shipment creation failing without ever rolling back a captured payment. Premium ghee customers expect a polished checkout, accurate inventory, and live tracking from day one.
What we built
A three-service architecture: a Next.js storefront with a Razorpay checkout modal, a separate Next.js admin panel for catalog and order ops, and a NestJS REST API on PostgreSQL with Redis. Versioned endpoints under /api/v1/ cover the full lifecycle - product catalog with ISR, stateful cart with guest-merge, transactional order placement with pessimistic stock locks, Razorpay capture with client-verify + webhook + admin reconciliation, and Shiprocket shipment orchestration with AWB assignment and live tracking. Storefronts deploy to Vercel; the API runs on ECS Fargate with RDS, Redis ElastiCache, and S3 + CloudFront for media.
Key features
Storefront & Cart
- Next.js 14 storefront with Tailwind, responsive product grid, and ISR-cached PDPs
- Redux Toolkit cart with localStorage persistence and guest → authenticated merge
- Razorpay checkout modal with client-side signature verification (HMAC-SHA256)
- Live stock availability and low-stock warnings on the product page
- Address book, order list, and tracking page tied to a customer's account
Payments
- Razorpay smart-collect with live + mock modes for offline development
- Webhook idempotency: payment.captured and order.paid events deduplicated server-side
- Triple-path reconciliation: client verify, webhook, and admin reverify all converge on a single atomic capture
- Admin reverify endpoint pulls live state from Razorpay to recover stuck or abandoned payments
Inventory & Orders
- Transactional order placement with TypeORM pessimistic_write locks on product rows
- Conditional stock decrement (WHERE stock >= qty) to prevent overselling under concurrency
- JSONB address snapshot on orders so a later address edit never mutates a shipped order's record
- Order state machine: pending_payment → paid → shipped → delivered/cancelled/refunded
- Free-shipping threshold logic (₹999+) with flat ₹49 fee below
Shipping & Tracking
- Shiprocket order creation, AWB assignment, label and manifest generation
- Webhook ingestion mapping 10+ Shiprocket status IDs to internal states with regex fallback on status text
- Auto-shipment creation triggered after payment capture, fire-and-forget with idempotent admin retry
- Customer tracking endpoint surfacing live EDD and event history from Shiprocket
- Graceful degradation - if Shiprocket is unreachable, local shipment state is preserved and retried
Images & Admin
- Sharp pipeline generating four WebP variants per upload: full, medium (600px), thumb (160px), and blur (24px)
- S3 PutObject in parallel; frontend swaps suffix dynamically for responsive loading
- Immutable cache headers (max-age=31536000) for CDN efficiency
- Admin dashboard: revenue today, low-stock alerts, pending payments, and shipment recovery
- Soft-delete (isActive) plus hard-delete with referential validation
Challenges solved
Transactional row-level locking for race-free stock
OrdersService.place() acquires pessimistic_write locks per product row, then decrements conditionally (WHERE stock >= qty). Concurrent orders that lose the race get a ConflictException - no overselling, no distributed locks needed.
Fire-and-forget shipment with idempotent recovery
Shipment creation runs via setImmediate after payment commit, so a Shiprocket outage never rolls back a captured payment. The admin's Create-shipment button is idempotent, serving as a manual retry.
Webhook idempotency + triple-path payment reconciliation
A single payment can be finalized via client verify, Razorpay webhook, or admin reverify. All three converge on one atomic capture() that becomes a no-op on retries - safe across tab closes, slow networks, and clock skew.
Shiprocket status mapping with ID + regex fallback
12 internal states mapped from 10+ Shiprocket status IDs, with case-insensitive regex on status text catching anything new. Order and shipment status update in the same write so the admin view never drifts.
S3 image variants with client-side suffix swap
Four WebP variants generated server-side and stored under a single base key; the frontend swaps suffixes (full.webp → full-thumb.webp) for responsive loading. The 24px blur variant doubles as a CSS background placeholder.
Guest-to-authenticated cart merge
On login, the guest cart is collapsed by product, validated against the live catalog, then upserted with ON CONFLICT and LEAST(qty, MAX_QTY_PER_LINE). Stale items drop silently - no UX-breaking errors on a deleted SKU.
Full-stack mock mode for offline development
RAZORPAY_MOCK and SHIPROCKET_MOCK flags swap in deterministic responses (order_mock_*, MOCKAWB*, fake EDD). The team can ship and test the entire happy path without live credentials.
Outcomes
Integrated
Payment gateway
Managed
Inventory
Automated
Shipment
Have a product idea or a system to scale?
Tell us what you're building. You'll hear back within one business day - from a senior engineer, not a sales rep.
- Free 30-min discovery call
- Fixed-scope or T&M engagements
- NDA on request - first reply within 24h
