Cambay
An online shop for Indian suits, kurta sets, sarees and lehengas in Canada, with dated delivery estimates and sales tax worked out for each province.
- Year
- 2026
- Status
- Live at cambaylabel.com
The problem
Before paying for clothes online, a shopper needs to know which size to choose, when each piece will arrive, and what the order will cost once shipping and their province's sales tax are added.
Cambay’s catalogue is Indian suits, kurta sets, sarees and lehengas, for shoppers in Canada. Some pieces are ready to wear and some are made to order, so arrival times differ from piece to piece. Sizes run from XS to XXXL, and some pieces come in one free size. Prices are in Canadian dollars, and the sales tax on an order depends on the province it ships to.
What we built
A storefront with size charts, dated delivery estimates, search that knows how shoppers spell, and a four-step card checkout, on a backend with staff roles, an audit log and a daily list of what needs doing.
We designed and built the storefront and the backend behind it.
Finding a piece
The catalogue is sorted into suits, kurtas, sarees, lehengas and dresses, and can be filtered by colour, with a count beside each colour. Search understands the spellings people type: a search for “lengha” finds lehengas and says “Showing results for lehenga”, and “kurtas” and “salwar kameez” work the same way.
A multi-buy saving comes off the cart by itself, and the cart says how many more pieces reach the next saving.
Fit and delivery
Each sized product has its own size chart, opened from the product page, with a switch between inches and centimetres. The chart gives garment measurements, which run larger than the body they fit. A size guide page explains how to measure, and how suits, lehengas and gowns are meant to fit.
Each product page shows a delivery estimate as a range of dates, and a made-to-order piece shows its own, later dates. The cart and checkout show the estimate for the whole order. The dates are counted in business days, skipping weekends and the holidays when carriers are closed.
Checkout
Checkout has four steps: contact and shipping, delivery, payment, and review. A shopper can check out as a guest or sign in. The province list covers all 13 provinces and territories, and the tax follows the address: GST or HST, and provincial sales tax where it applies, with rates checked against the Canada Revenue Agency and provincial sources.
Cards are taken through Stripe. Checkout only authorizes the card, and the payment is captured afterwards.
Shipping is built on Stallion Express, which can price an order at Canada Post’s live rates during checkout, buy the label when the order ships, and mark the parcel delivered (a job checks twice a day). When no live rate comes back, checkout falls back to flat standard and express rates, and a priority option is offered too.
The backend already holds a second region, the United States in US dollars, which the shop keeps closed for now: an address under /us goes to the same page under /ca.
After the order
Signed-in customers request a return from their order history and choose one of five reasons. The backend refuses a request after the return window has closed, or for an order that is not theirs. Order, shipping, return, refund and password emails are written as React Email templates and sent through Resend.
Running the shop
Every staff account has one role: Owner, Catalogue, Fulfilment or Support. Each role can do only the parts of the admin its work needs. A Catalogue account edits products but never sees an order, and only an Owner can refund. One check runs on every admin request.
A Today page lists what needs doing: payments to take, payments about to lapse, orders to pack by the day promised, parcels not delivered after 10 days, returns on their way, refunds to make, drafts, thin margins and low stock. Each list shows only to the roles that act on it.
A product cannot be published until every variant of it (each size, for example) has a price in Canadian and US dollars, a 10-digit US tariff code, its country of origin, its material, its weight and its dimensions, and the product has a photo. Products can be added from a spreadsheet: a trial run lists every problem by row before anything is saved, and the photos are copied into the shop’s own storage.
Result
Cambay is live at cambaylabel.com for shoppers in Canada, with prices in Canadian dollars.
Technical notes
How it is built
The backend runs on Medusa 2, an open-source commerce engine, with PostgreSQL 16 and Redis 7. It runs on one rented server as a set of Docker containers: the backend, a worker for scheduled jobs, the database, Redis, a backup service and Caddy, a web server that is the only one open to the internet. The storefront is Next.js 15 with React 19 and Tailwind CSS, hosted on Vercel. One storefront app can serve more than one shop: it reads the shop from the web address, and each address sees only its own catalogue, cart and theme.
Photos are stored in Cloudflare R2 and served as AVIF or WebP at 480, 1080 or 1920 pixels wide. The shop’s settings (regions, tax rates, shipping options and categories) are kept as code and applied by one setup script, which can run again without creating anything twice.
Every change runs through automatic checks on GitHub Actions (CI): the backend’s unit tests, its integration tests against real PostgreSQL and Redis, and the storefront’s type checks, lint, unit tests and build, then an audit of dependencies for known vulnerabilities. A deploy script backs up the database first, runs the database changes, restarts the services, keeps the previous version ready to roll back to, and checks that the shop answers.
The database is backed up every night to Cloudflare R2 and kept for 30 days. A health check fails if no backup has arrived for 26 hours, and a backup can be test-restored without touching the live database.
Security
Caddy passes only the shop’s API, sign-in, incoming webhooks (such as Stripe’s payment notices) and a health check to the backend, and answers everything else with “not found”. The admin sits behind Cloudflare Access, so it asks for a login before it loads at all.
The audit log records refunds made from the admin, price edits, deletions and changes of staff role, with who made each one and when. A refund is written to the log before any money moves. The log is append-only: a database rule refuses edits and deletions of its entries, and a test fails if any route that can refund, delete or change a price has no audit rule.
Analytics (PostHog) go through the shop’s own address and never load for a visitor whose browser asks not to be tracked. Visitors can turn them off in the footer of every page, and no session is recorded.
Next case study
Start a project
Tell us what you need built.
Send a few lines about your business and what you have in mind. We reply within one business day, book a 30‑minute call if it makes sense, and send a fixed quote in writing after that.
Or call 647-252-5352, Monday to Friday, 9 am to 6 pm Toronto time.