Show me product, variant, SKU and listing as tables, and the mistake of conflating them.
Four words candidates use interchangeably, and the schema is where the confusion becomes expensive.
product the thing a customer shops for. Marketing lives here.
product_id, title, description, brand, category_id, status
variant one buyable configuration of that product. Options live here.
variant_id, product_id, option_values {colour: navy, size: M},
barcode, weight_grams, status
sku the stock-keeping unit. Inventory is counted against this.
sku_id, variant_id, pack_size, supplier_ref
listing the offer: this SKU, on this channel, by this seller, at this price.
listing_id, sku_id, channel_id, seller_id, price_minor, currency,
valid_from, valid_to, listing_status
The conflation that hurts, seen constantly:
product(id, title, colour, size, price, stock_count)
The flat table cannot express a t-shirt. Navy medium and navy large are separate things to count, ship and photograph, but one thing to describe and rank, and a single row forces you to choose which. Teams that choose product duplicate the description eight times and diverge; teams that choose variant lose the concept a customer actually searches for.
Separating SKU from variant looks like over-modelling until a supplier ships the same navy medium as a single and as a pack of three, or until two variants share one physical item under different barcodes. Inventory is counted against the thing on the shelf, which is the SKU, and price is quoted against the thing on offer, which is the listing.
The listing is the entity most people omit, and it is the one that decides
whether you can ever become a marketplace or sell on a second channel. Price,
availability and even title vary by channel and by seller, so they belong on an
offer row and not on the product. A price column on the product means every
subsequent requirement — a different price in Ireland, a marketplace seller
undercutting you, a wholesale tier — becomes a schema migration.
The effective dating on the listing is what makes a price change auditable. A mutated price column answers "what does this cost" and nothing else, and the question you will actually be asked is what it cost on the fourteenth of March, by a customer holding a screenshot.