Back to work
E-Commerce·2026

Lumiere

A luxury handcrafted-candle storefront with a queue-driven order pipeline — payments, branded emails, PDF invoices, fulfillment and loyalty run end-to-end with no manual intervention.

Role
Solo Full-Stack Developer
Year
2026
Category
E-Commerce
Platform
Web App
Stack
ReactViteTypeScriptFastifyPrismaPostgreSQLRedisBullMQRazorpay
Lumiere luxury candle storefront
01

Why I built this

Selling premium candles meant the customer experience had to feel luxury-grade — branded order emails with PDF invoices, SMS and WhatsApp updates, loyalty points — while the operator needed resilience: retries, idempotency and alerting, 'so there is no manual intervention once payments land.' Lumiere's whole backend is designed around that promise, with a design target of scaling to high user volume with proper infrastructure.

02

How it works

Storefront catalog and discovery

Real-time search modal, category and collection filters synced to the URL, product cards with a waitlist CTA when sold out, and Framer Motion page transitions across a 13-product catalog.

Self-built auth

JWT access tokens (15m) with hashed, rotating refresh tokens (30d), per-route rate limits, Google Identity Services login, and auth-gated cart, wishlist and checkout flows.

Webhook-driven order automation

The Razorpay payment.captured webhook is the source of truth. It fans out to queues that send branded email/SMS/WhatsApp confirmations with a generated PDF invoice, create Shiprocket shipments with AWB tracking, deduct stock atomically with low-stock alerts, and update the live order status.

Super-admin panel and loyalty

A dashboard with product CRUD and a draft workflow, a review queue, and an automation timeline — plus a loyalty engine (1 point per ₹10 on delivery, birthday bonuses, win-back rewards).

03

Key decisions

Payment and order state transitions are driven by verified provider webhooks with dedupe — which survived the UPI delayed-capture edge case (authorized wait state, then captured confirmation).

Eight BullMQ queues with 3-attempt exponential backoff and idempotent job IDs (stage + orderId); terminal failures alert via Slack/email. Nothing is retried blindly.

Automation stages promote sequentially (1+2 → 3 → remaining) via an AUTOMATION_RELEASE_STAGES gate, so the pipeline proves itself incrementally in production.

04

Backend architecture

Modular Fastify monolith

Modules isolate auth, account, admin, orders, payments, products, cart, wishlist, reviews, automation, notifications, fulfillment, refunds, reports, webhooks and health, with centralized env validation and security plugins.

Eight BullMQ queues on shared Redis

automation-stage, notifications, fulfillment, inventory, post-delivery, reports, refunds and admin-alert — every stage with retries, persisted automation logs and alert paths.

20 Prisma models with webhook dedupe

Orders, payments, shipments, automation logs, rewards and returns, with a WebhookEvent(provider, eventId) uniqueness constraint so duplicate deliveries are harmless.

JWT + refresh rotation

Access tokens expire in 15 minutes; refresh tokens are stored hashed, rotated on use, and rate-limited per route (signup 3/min, login 5/min, refresh 10/min).

05

Challenges

High

OAuth security debt

An empty GOOGLE_CLIENT_ID after secret rotation, no PKCE, no MFA or email verification, and refresh tokens refreshable indefinitely within 30 days — documented and flagged for production hardening.

Medium

Launch-readiness gaps

The auth modal overlapped the cart drawer for guests, cart/wishlist were localStorage-only with backend persistence still TODO, and high-volume DB indexes on Order and AutomationLog were missing.

Medium

Docker/Render debugging friction

Four consecutive commits debugged the container: OpenSSL missing for Prisma, a bad health-check path, and a temporarily removed migrate command before landing on a working Render Dockerfile with migrate split from startup.

06

What I learned

  • Verified webhooks with dedupe are the only safe source of truth for money-driven state.

  • Idempotency plus staged rollout gates beat big-bang releases.

  • A blueprint-first workflow — execution.md → progress.md → prelaunch.md → launch-readiness.md — kept a solo build on track.

Code snippets

backend/src/queues/bull.tstypescript
export const automationQueue = new Queue('automation-stage', { connection });
export const notificationQueue = new Queue('notifications', { connection });
export const fulfillmentQueue = new Queue('fulfillment', { connection });
export const inventoryQueue = new Queue('inventory', { connection });
export const postDeliveryQueue = new Queue('post-delivery', { connection });
export const reportsQueue = new Queue('reports', { connection });
export const refundsQueue = new Queue('refunds', { connection });
export const adminAlertQueue = new Queue('admin-alert', { connection });