Off Shopify, onto a custom storefront with its own inventory + ops system
Results at a glance
Platform
Shopify · template-bound · per-month fees climbing
Custom Next.js storefront, owned end-to-end
Inventory + ops
Shopify's basic counter, no audit trail, no PO flow
Dedicated ops dashboard with race-safe stock, low-stock alerts, supplier + PO workflow, full audit history
Marketing content
Shopify theme editor, code changes for every copy tweak
Headless CMS, owner edits live content himself
The situation
A growing apparel brand, selling both direct-to-consumer and B2B (wholesale), was running on Shopify and had hit the place every Shopify business eventually hits: the platform fits the easy 80% and fights you on the rest. Themes constrain the brand. Inventory logic is a black box. Bundle discounts don't quite work the way the founder wants them to. Adding a new field to the customer flow requires a third-party app, and that app has its own subscription, and now there are four. The monthly bill was creeping; the design and the operations were both stuck inside someone else's product.
The brand wanted to look and run like itself, not like Shopify.
What we built
- Custom discount + bundle engine: DB-backed rules, stackable bundles (3-pack at one price, 6-pack at another, applied greedily to the cart), owner-tunable in the dashboard. No more "Shopify won't let me run this kind of deal."
- Headless CMS for marketing content: Hero copy, manifesto, FAQ, collaboration callouts, footer, navigation, all editable by the owner through a dedicated content interface. Code changes only when the *structure* changes, not when the copy does.
- Magic-link auth + rate-limited account flows: Customer accounts, order history gated to the signed-in customer (no more open `/orders/lookup` privacy leaks), branded transactional emails through the brand's own domain.
- Newsletter system: Signup endpoint with email validation + dedupe, subscriber dashboard with CSV export. No third-party email-app subscription required.
- Inventory: Per-size stock, race-safe `decrement_stock` writes on every paid order, full adjustment history with reason codes (sale / correction / return / receive), low-stock view, daily low-stock email cron.
- Suppliers + purchase orders: Draft → sent → partial-received → received, atomic via a Postgres function, with stock + audit rows written in the same transaction.
- Orders + refunds: Stripe refund flow with optional restock, voids, partial refunds, all reconciled against Stripe and the brand's books.
- Reports: Margin, sell-through, valuation: actual numbers, not a black-box "trending up" chart.
- Command palette: ⌘K to jump anywhere. Built for someone who actually uses the tool every day.
Two applications, sharing one database, designed to fit each other.
### The customer-facing storefront
A fully custom Next.js site (product pages, custom cart, checkout, accounts, order tracking) designed to match the brand instead of fight a theme. Stripe Elements drives checkout (custom UI, not the hosted Stripe page) so the buying flow stays on-brand all the way through.
### The dedicated ops dashboard
A separate Next.js app the owner uses to actually run the business. This is what Shopify Admin tried to be, but built for *this* brand's workflow.
How it changed the work
The brand owns its software. Adding a new payment method is a 30-minute change, not a third-party app subscription. Running a 6-pack bundle promo for the holidays is a form, not a workaround. The Shopify-shaped wall is gone.
And the ops dashboard means the day-to-day (taking inventory, receiving a PO, refunding an order) happens in a tool built for it. Not in a generic admin trying to be all things to every store.
Engagement details
- Type:: Multi-phase larger build
- Stack:: Next.js · Supabase (with race-safe Postgres functions for stock) · Stripe Elements + Stripe Terminal · Sanity for CMS · custom auth on top of Supabase Auth
- Two repos, one Supabase project: keeps customer + ops aligned and the database the single source of truth.
- Ongoing:: Maintenance and small iterations on retainer. Brand owns the code.