Lia Fashion
A fashion boutique selling online and over the counter, on one stock pool. Web store, admin, in-store POS and supplier purchasing in a single Laravel platform.

Lia Fashion sells clothing on the web and from a physical counter. MnT Future built the platform behind both: a Laravel 12 REST API with a customer storefront, a full admin back office, an in-store POS, and supplier purchasing. The part that matters is that all of it reads and writes one inventory. A size sold at the till and a size sold online decrement the same row, under a lock, so the two channels cannot oversell each other. That is the same problem a US brand has the day it opens a retail door or a pop-up, and the same problem a marketplace has across fulfilment locations.
One garment, two tills
A boutique that sells in two places has one hard problem and a lot of easy ones. The hard one is that there is a single physical garment, in a single size, and two tills that can sell it. Run the shop floor on one system and the website on another and you oversell: the customer pays, and someone has to make an apology call. Everything else follows from that. Stock has to be tracked per colour and per size rather than per product, because a medium selling out is not the product selling out. Payments have to be reconciled rather than assumed, because a payment that succeeds at the gateway and fails to come back leaves an order in limbo. And the people running the shop needed the whole thing, including what they buy from suppliers, in one back office rather than three.
A senior-led path from idea to live.
Model stock at the size, not the product
Every product carries its sizes as structured data with stock and price on each one, and colour variants carry their own imagery. Nothing in the system talks about a product being in stock, only a specific size of it.
Make the two channels share one write path
The POS does not get its own inventory logic. A counter sale and a web order call the same stock decrement, inside a database transaction that locks the product row until the sale commits, so two simultaneous sales of the last item cannot both succeed.
Treat payment as something to verify, not assume
Razorpay orders are created server-side, signatures verified, and webhooks handled. On top of that a scheduled command re-checks payments still sitting pending and reconciles them against the gateway, so a dropped callback becomes a resolved order instead of a support ticket.
Put the back office in one place
Orders, catalogue, coupons, banners, offers, shipping rules, reports, invoice settings, POS and supplier purchasing all live in the same admin, on the same auth, against the same data.
What we built
For shoppers
- Catalogue with colour variants, each carrying its own gallery, and stock and price held per size
- Registration by email OTP, or Google sign-in, with saved addresses and profile
- Cart that applies bulk pricing on the total quantity of a line, not per add-to-cart, so splitting an order does not change the price
- Coupon validation, tax and shipping rules applied at checkout
- Razorpay checkout with server-side order creation and signature verification
- Order tracking, with fulfilment raised automatically once payment clears
For the store team
- In-store POS for counter sales, with its own invoice numbering and walk-in customer records
- POS sales decrement the same size-level stock as the website, under a row lock, so the channels cannot oversell each other
- Catalogue, category, coupon, banner and offer management with Cloudinary-hosted media
- Order and transaction management, with pending payments reconcilable on demand
- Supplier records and purchase entries, so incoming stock is captured where the outgoing stock lives
- Reports exported as PDF or CSV, plus a dashboard over sales and orders
- Company, invoice and payment-gateway settings editable without a deploy
What we shipped, on screen.

The storefront
The catalogue customers browse. Colour variants carry their own imagery, and availability is resolved per size rather than per product.

Colour and size, priced separately
Picking a colour swaps the gallery; picking a size resolves stock and price. The size is what the rest of the system tracks.
Where the hard problems were.
The decisions that keep a two-channel shop honest about what it actually has in stock.
One inventory, two channels
The website and the shop counter write to the same size-level stock. There is no nightly sync to go wrong, because there is nothing to sync.
The last item can only sell once
Stock decrements run inside a transaction that locks the product row, so two concurrent sales cannot both read the same stock and overwrite each other.
Payments get reconciled, not assumed
A command re-checks pending Razorpay payments against the gateway and resolves them, so a dropped webhook does not leave a paying customer without an order.
Buying and selling in one back office
Supplier records and purchase entries sit beside the catalogue and orders, so what comes in and what goes out are the same system.
Engineering decisions
Every technology earned its place by solving a specific problem better than the alternatives.
Sizes as structured data on the product
Used for: Stock and price are held per size, and the API resolves availability at that level.
Advantage: A medium selling out does not hide the product. Apparel lives or dies on this, and bolting it on later means rewriting every stock path.
lockForUpdate inside the sale transaction
Used for: The product row is locked while stock is decremented, for POS and web alike.
Advantage: Two tills selling the last item at the same moment cannot both succeed. Without the lock both reads see the same stock and the second write silently restores it.
Scheduled payment reconciliation
Used for: An artisan command verifies pending payments against Razorpay, individually or in bulk.
Advantage: Gateway callbacks fail. This turns a class of silent revenue loss into a job that runs, which is unglamorous and worth more than most features.
Shiprocket raised on payment, not on order
Used for: Fulfilment is created once money has actually cleared.
Advantage: Nothing ships against an unpaid order, and the shop team never has to check twice before packing.
Laravel Sanctum with OTP and Google sign-in
Used for: Bearer tokens for the API, email-OTP registration, and Google OAuth alongside it.
Advantage: One token model covers storefront, admin and POS, so a permission is enforced in one place rather than three.
What it's built on.
- Laravel 12
- PHP 8.2
- MySQL
- Sanctum
- Razorpay
- Shiprocket
- Cloudinary
- DomPDF
- React
- Vite
- Tailwind CSS
The questions buyers ask about this build.
No. It is a single-brand fashion business selling its own stock, online and over the counter. The vendor records in the platform are suppliers it buys stock from, not sellers on a marketplace. Our two-sided marketplace work is LOBBI, which is a separate story.
Because a garment in a given size exists once. If the website and the shop floor keep separate counts, the first busy Saturday produces an oversell, a refund and an apology. Sharing one write path removes the failure instead of monitoring for it.
The engineering transfers directly: variant-level inventory, one stock pool across channels, concurrency-safe stock writes, and payment reconciliation. The US-specific layer differs, so a US build swaps Razorpay for Stripe, Shiprocket for a US carrier integration, and adds the sales-tax engine and the ADA and PCI work we do as standard.
Yes. Architecture, the Laravel API, the admin back office, the POS, and the payment and fulfilment integrations. Published here with Lia Fashion's permission.
Selling in more than one place?
If your store and your retail, wholesale or pop-up channels keep separate stock, that is a rebuild worth scoping properly. Bring it to a free strategy session and we will map it.
