Imoran ai LogoImoran ai Logo

FASCO: Modern E-Commerce User Flow with React & Supabase

How I built the shopper side of Fasco, a React + Vite + Supabase fashion store: persistent carts, real product filtering, and a checkout that only marks an order paid once the payment webhook confirms it.

Published: November 12, 2025

Last updated: June 30, 2026

image of the article

I built Fasco as a real fashion storefront, not a demo. This post is about the half customers actually touch: the shop, the cart, and checkout. The admin panel has its own writeup.

You can click around the live build here: https://fasco-sooty.vercel.app/

Why I make you sign in before adding to cart

Most tutorials let anyone fill a cart and only ask for an account at checkout. I went the other way. On Fasco you sign in before you can add anything or save a favorite.

The reason was practical. The cart isn't local state I throw away on refresh. It lives in Supabase, tied to your account, so it's still there when you come back tomorrow on a different device. That only works if I know who you are up front. The cost is a little more friction early on. Since I also wanted favorites and abandoned-cart recovery to work, it was worth it.

The shop page and filtering

The shop page filters on size, price range, category, and rating. Nothing exotic, but I spent real time making the filters feel instant instead of triggering a full reload on every click. React and Vite did most of the heavy lifting, and the dev loop was fast enough that I actually enjoyed tuning this part.

Light and dark mode are both there. I default to the system setting and let people override it.

Checkout: Stripe and Paystack

Fasco takes payments through two providers. Stripe handles international cards, Paystack handles local ones. Picking the right gateway for the buyer turned out to be fiddlier than either integration on its own.

The part I'm proud of is how an order becomes "Paid." It never happens in the browser. The frontend starts the payment, but the order status in the database stays "pending" until the payment provider sends a webhook back to my server confirming the money actually moved.

If you mark an order paid from the client, you're trusting the browser. Don't.

Roughly, the flow looks like this:

// client starts checkout; the order is created as "pending"
const order = await createOrder({ items, status: "pending" })

// later, on the server: Stripe/Paystack calls this webhook
export async function handleWebhook(event) {
  if (event.type === "payment.success") {
    await supabase
      .from("orders")
      .update({ status: "paid" })
      .eq("id", event.metadata.orderId)
  }
}

That one rule, only the webhook can flip an order to paid, killed a whole class of fake orders before they could exist.

Supabase doing the unglamorous work

Two things made Supabase the right call. First, row-level security: a policy makes sure you only ever read your own orders, while an admin can read everything. I'm not filtering by user in the frontend and hoping the query is right. The database refuses to hand over rows that aren't yours. Second, persistence: cart contents, quantities, and the running total with tax and shipping all survive a refresh, because they live server-side instead of in component state.

What I'd tell past me

Build the payment-confirmation flow first, before any of the pretty parts. I wired up the UI early and then had to bend it around the webhook reality later. Start from "how do I know this money is real," and the rest of checkout falls into place.

Frequently asked questions

Why does Fasco make you sign in before adding to cart?

The cart lives in Supabase tied to your account, so it persists across devices and sessions and powers features like favourites and abandoned-cart recovery. The tradeoff is a little more friction up front, which was worth it here.

How are payments verified in the store?

An order only becomes "Paid" when Stripe or Paystack sends a verified webhook to the server. The browser never marks an order paid, which blocks fake or unpaid orders.

Can you build a store like this for me?

Yes. I build custom storefronts with React or Next.js, Supabase, and Stripe/Paystack. Tell me what you're selling and I'll outline an approach.

Let's Work
Together

Hand Reaching

Have a project in mind? We'd love to hear about it. Let's create something great together!

PRODUCT DEVELOPERUI ENGINEERMVP DEVELOPMENTFRONTEND DEVELOPMENTPRODUCT DEVELOPERUI ENGINEERMVP DEVELOPMENTFRONTEND DEVELOPMENTPRODUCT DEVELOPERUI ENGINEERMVP DEVELOPMENTFRONTEND DEVELOPMENT