Feature · Product design​

City Hive Bulk upload .CSV order creation

Upload a spreadsheet, create an order. The design problem was everything that goes wrong in between.

Research → UX → UI → Handoff

Add to cart

TL;DR

"There should be an API end point that allows authenticated users to send an excel listing of products and to have cart created and ready for them.
Apparently a common use case for bars and restaurants." - and so a journey began.

Company — City Hive, a beverage e-commerce platform
Role — Product Designer (end-to-end: research, UX, UI, spec)
Surfaces — Merchant dashboard, storefront
Year — 2025
Shipped — Yes, merchant dashboard first

HOW I READ IT

Where we start

The request assumed a clean file. In beverage retail it almost never is.

A bar manager exports an order from their own inventory system and sends it over. Some barcodes are stale, some belong to a different distributor, some rows have no quantity at all. A few products match several sizes — 50ml, 200ml, a 12-pack — and the file doesn't say which. A few are out of stock today.

An endpoint handles this by returning an error array. That leaves someone with a 167-line order and no idea which lines failed or what to do about them.

So I treated the upload as the easy half. The design problem was what happens to the rows that don't match — and whether someone can finish their order anyway.

CSV upload flow with shared cart conflict across both surfacesA flowchart where merchant dashboard and customer storefront entry points converge immediately at a shared cart-conflict step, then run one shared path through column mapping, catalogue matching, three outcomes, and resolution to a finished cart.MerchantFrom inside an orderCustomerUpload cart pageCart already has items?Keep or removeMap columnsBarcode, quantity, unitMatch catalogBy barcodeAll matchedNothing to resolveSome issuesMissing, multiple, OOSNone matchedDead endReview and fixChoose or drop itemsFix and retryExport failed barcodesCartReady to check outMerchant entryCustomer entryRecoveryResult