Home / Help Center / pos-app-garment / garment / Size Curve Analysis
🗂️ garment

Size Curve Analysis

Size Curve Analysis compares how your actual sales split across sizes (XS/S/M/L/XL…) for each product category against a built-in "ideal" benchmark curve, so you can see at a glance which sizes you are over-selling or under-selling and adjust your next buy accordingly.

📍 Menu path: /garment/size-curve
👤 Who uses it: Owner,Manager

Overview

For a chosen date range (and optional category/brand filter), the page fetches every sale-item sold for products in that scope, works out each item's size from the matching product variant's stored attributes, and groups quantity sold by size within each product category.

Each category's actual distribution is shown as a percentage of that category's total units sold per size, and is compared against a hardcoded "ideal curve" table baked into the frontend — five preset curves (Default, Shirts, Trousers, Kurtis, Tops) chosen by matching the category name against keywords (e.g. any category containing "SHIRT" uses the Shirts curve, "TROUSER"/"PANT"/"JEANS" uses Trousers, etc.), falling back to a generic Default curve otherwise.

Each size is rendered as a paired bar (actual % vs ideal %) with a variance badge above it; a variance beyond +5 or −5 percentage points is called out as clearly over-sold (red) or under-sold (green) respectively, with a plain-language insight line at the bottom of each category card ("Over-sold: L — order more next season").

The "Show ideal curve" checkbox toggles whether the benchmark bars/variance are shown at all, letting you view just your raw actual distribution if preferred.

This analysis depends entirely on products having size recorded via variant attributes (i.e. set up through Variant Matrix or equivalent) — products without size-tagged variants cannot be attributed to any size bucket by this report.

Before You Start

Step-by-Step Guide

1 Run a size curve analysis

  1. Set From and To (defaults to the last 90 days).
  2. Optionally choose a Category from the dropdown (populated from categories returned by the last data pull) or type a Brand to narrow further.
  3. Click Apply to load the report.
  4. Leave "Show ideal curve" checked to see the benchmark comparison, or uncheck it to see only your actual sales split.

2 Read one category's bar chart

  1. Each category gets its own card, titled with the category name and total units sold.
  2. For every size, a solid bar shows Actual % and (if enabled) a lighter amber bar shows Ideal %, with the exact percentage and units-sold figure printed underneath.
  3. A small variance badge above each size (e.g. "+8%" in red, "-6%" in green) shows how far actual is from ideal for that size specifically.

3 Act on the insight line

  1. Read the insight strip below each category's chart — it lists which sizes are meaningfully Over-sold (more than 5 points above ideal) and which are Under-sold (more than 5 points below ideal).
  2. Use "Over-sold" sizes as a signal to order more of that size next season for that category, and "Under-sold" sizes as a signal to cut back.
  3. A category with no sizes more than 5 points off the ideal curve shows no insight line at all — its current buying pattern already roughly matches the benchmark.

4 Export the analysis

  1. After Apply loads data, click the CSV button.
  2. A file named size-curve-{from}-to-{to}.csv downloads with one row per category/size combination: Category, Size, Qty Sold, Actual %, Ideal %, Variance %.

Every Field & Button, Explained

Field / ButtonWhat it does
From / ToDate range for the sales analysed; defaults to the last 90 days ("a season") through today.
Category filterOptional; narrows to one product category. Options are populated from the categories seen in the last loaded report, not a separate lookup.
Brand filterOptional free-text filter on product brand.
Show ideal curve checkboxToggles whether the amber "ideal" bars, variance badges and insight strip are shown; actual-sales bars always show regardless.
ApplyRuns the query against the selected date range/filters.
CSVExports the currently loaded report to CSV; only appears once a report with at least one category has loaded.
Category card total ("N units sold")Sum of quantity sold across every size for that category in the date range.
Actual bar / Ideal barPer-size solid bar (your real sales %) and lighter amber bar (benchmark ideal %); heights are proportional to percentage with a small minimum so a 0% bar is still visible.
Variance badgeActual % minus Ideal % for that size, shown above the bars in red (over-sold, >+5), green (under-sold, <-5) or grey (roughly on target).
Over-sold / Under-sold insight lineLists every size whose variance exceeds ±5 percentage points for that category; omitted entirely when every size is within the ±5 band.

Tips & Best Practices

Troubleshooting & FAQ

The page says "No size sales data found" even though I have sales in this period.
This report can only bucket a sale by size if the product sold has a size-tagged variant (set up through Variant Matrix or similar) — sales of products without size variants are excluded entirely from this report, not shown as "Unknown".
A size shows as UNKNOWN in the chart.
A sold item is bucketed as UNKNOWN when its SKU could not be matched to a variant carrying a recorded size attribute — check that the specific variant sold actually has its size field filled in via Variant Matrix.
My category doesn't match any of the five ideal-curve types listed in this article — what benchmark does it use?
Category names are matched by simple keyword search (e.g. containing "SHIRT", "TROUSER"/"PANT"/"JEANS", "KURTI"/"KURTA", "TOP"/"BLOUSE"); anything that doesn't match one of those keyword groups falls back to a generic Default ideal curve, which may not reflect that category's real-world size spread well.
The Category dropdown is empty until I run a report once.
Category options are populated from the previous report's results, not a separate category lookup — run an unfiltered Apply first to populate the list, then refine with a specific category.
Variance badges disappear when I uncheck "Show ideal curve".
That checkbox hides the entire ideal-vs-actual comparison (ideal bars, variance badges, and the over/under-sold insight line) — it is meant for viewing just the raw actual distribution; recheck it to bring the comparison back.

🧑‍💻 Developer Notes

Source component(s):

  • frontend-app/pos-app-garment/src/pages/garment/SizeCurveAnalysisPage.jsx

Backend endpoints used:

  • GET /garment/analytics/size-curve

Related tables (db-core repositories):

  • Product
  • ProductVariant
  • Sale
  • SaleItem

Redux slices:

  • None — local component state only (useState/useCallback)

Feature flag key: reports

Backend handler is getSizeCurveAnalysis in packages/pos-core/src/garment.js: it loads every ProductVariant for the tenant up front (not scoped to the queried products), builds a SKU→size lookup by parsing each variant's attributes JSON, then loads matching products (filtered by tenant/category/brand) and sale items within the date range, aggregating quantity sold per size within each product category. The five "ideal curve" benchmark tables (DEFAULT, SHIRTS, TROUSERS, KURTIS, TOPS) are hardcoded constants inside the frontend component itself (IDEAL_CURVES in SizeCurveAnalysisPage.jsx) — they are not stored in the database, not configurable per store, and not shared with the backend in any way, so the CSV export recomputes the same ideal percentages client-side purely for the exported rows. Category-to-curve matching is a simple case-insensitive .includes() keyword check with no fuzzy matching, so a category named e.g. "Denim" (rather than containing "TROUSER"/"PANT"/"JEANS") would silently fall back to the generic Default curve instead of Trousers.