Case 01 / Ecommerce Platform

From no storefront to an owner-run coffee business.

Mendivil Coffee is a roaster in Walnut, California that had no way to sell online — orders arrived by word of mouth. I built them a custom Stripe-powered storefront from nothing: live in four weeks, then owner-managed two weeks later. They now create, price, archive, and restore their own coffees, and customers buy several bags in one order with a grind chosen per bag.

Zero to launch
4 weeks
To owner-managed
6 weeks
Test files
52

01 — Where it started

A roaster with nothing to sell on.

There was no online storefront. Not a thin one, not a marketplace listing — nothing. A customer who wanted a bag had to know someone. The business was getting off the ground and every order came through word of mouth, which caps how far it can travel.

So the brief was not a redesign or a migration. It was a storefront that did not exist yet, built to sell real coffee to real strangers on the first day it went live.

02 — Shipping first, then stepping out

Selling in four weeks. Self-serve in six.

Week 4

Live and taking orders

A custom Stripe-powered storefront where there had been none. One coffee, one hardcoded price, checkout that worked. Strangers could buy without knowing anybody — the thing word of mouth could never do.

Week 6

Handed to the owners

The catalog became theirs. Products created on demand in Stripe, priced, archived, and restored from an admin they run themselves, with a durable cart, per-bag grind selection, and deploy status they can actually read.

The first launch deliberately hardcoded a single coffee to one Stripe price. That was the right place to stop: it got them selling weeks earlier, and price changes were rare enough that routing them through me cost almost nothing. The second stage removed me from that loop before the catalog grew enough to make it a real bottleneck.

03 — Decisions that mattered

Four problems Stripe does not solve for you.

Stripe prices are immutable

You cannot edit a price in place. An owner price change creates a new one-time USD price, promotes it to the product's sole active purchasable price, and retires the previous one. Existing checkout sessions and stored order line items keep their historical price naturally, so past orders stay accurate without extra bookkeeping.

Carts key on product, not price

A saved cart line stores the Stripe product ID, never the mutable price ID. On checkout the server resolves each product against the active catalog and selects the current price. A cart saved before a price change is still valid afterward, and it charges today's price rather than a stale one.

The client never sends money

The server rejects empty carts, duplicate products, unknown or archived products, quantities other than one, unsupported grind preferences, and every client-supplied price or amount. The client expresses product intent; the server determines commercial truth. That split keeps the checkout surface small and the trust boundary obvious.

Archive, never delete

Discontinuing a coffee flips the Stripe product's active status. IDs, prices, metadata, the generated label image, and order line items all survive, so historical fulfillment records stay intact and a seasonal coffee can be restored later without being rebuilt.

04 — What it runs on

Boring where it counts.

Stripe holds commercial truth; Postgres holds the operation ledger that serializes catalog changes; blob storage holds generated label images. Nothing here is exotic, which is the point — the owners inherited a store their next developer can read.

NuxtPiniaStripeNetlify BlobsNeon PostgresSentryPlaywright

05 — Common questions

What people ask before building one.

What did Mendivil Coffee use before this?
Nothing. There was no online storefront and no way to buy from them on the internet — every order came through word of mouth. The site was built from scratch, live in four weeks.
How can a non-developer change a price if Stripe prices are immutable?
The admin creates a new one-time price behind the scenes, makes it the product's sole active purchasable price, and retires the old one. The owner sees a single price field. Historical orders keep the price they were charged, because retired prices are never deleted.
What stops a saved cart from charging an outdated price?
Cart lines store the Stripe product ID rather than the price ID, and the server resolves the current active price at checkout. Client-supplied amounts are rejected outright. A cart left open across a price change checks out correctly at the new price.
What happens to past orders when a coffee is discontinued?
Nothing. Archiving flips the product's active status rather than deleting it, so order line items, prices, and product metadata remain intact. The coffee disappears from the catalog, sitemap, and checkout validation, and can be restored later.
How do the owners know a catalog change actually went live?
Catalog changes trigger a site rebuild, and the rebuild used to be silent. Now catalog operations are serialized behind a database-enforced lock and move through explicit states — reserved, mutating, triggered, building, ready — so the owner sees one clear status instead of guessing whether a change took.