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.
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
- Products must have size-based variants (created via Variant Matrix, or any process that stores a
sizekey in ProductVariant.attributes) — sales of products without size variants cannot be broken down by size here. - There must be completed sales within the chosen date range for at least one size-tagged product, or the report shows an empty state.
- The "ideal" benchmark percentages are fixed constants in the frontend code, not configurable per store — they are described as general Indian-market industry benchmarks, not your own historical baseline.
Step-by-Step Guide
1 Run a size curve analysis
- Set From and To (defaults to the last 90 days).
- Optionally choose a Category from the dropdown (populated from categories returned by the last data pull) or type a Brand to narrow further.
- Click Apply to load the report.
- 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
- Each category gets its own card, titled with the category name and total units sold.
- 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.
- 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
- 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).
- 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.
- 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
- After Apply loads data, click the CSV button.
- A file named
size-curve-{from}-to-{to}.csvdownloads with one row per category/size combination: Category, Size, Qty Sold, Actual %, Ideal %, Variance %.
Every Field & Button, Explained
| Field / Button | What it does |
|---|---|
From / To | Date range for the sales analysed; defaults to the last 90 days ("a season") through today. |
Category filter | Optional; narrows to one product category. Options are populated from the categories seen in the last loaded report, not a separate lookup. |
Brand filter | Optional free-text filter on product brand. |
Show ideal curve checkbox | Toggles whether the amber "ideal" bars, variance badges and insight strip are shown; actual-sales bars always show regardless. |
Apply | Runs the query against the selected date range/filters. |
CSV | Exports 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 bar | Per-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 badge | Actual % 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 line | Lists every size whose variance exceeds ±5 percentage points for that category; omitted entirely when every size is within the ±5 band. |
Tips & Best Practices
- Run this once per season (matching the 90-day default window) rather than continuously — the "ideal" comparison is most useful as a season-end buying-plan input, not a daily metric.
- Set up size variants for every sellable garment category via Variant Matrix before relying on this report — any product sold without a recorded size is invisible to this analysis entirely.
- Treat the built-in "ideal" curves as a generic starting benchmark, not a guarantee — your own customer base may reasonably differ from the general Indian-market averages baked into the tool, especially for niche categories that fall back to the generic Default curve.
Troubleshooting & FAQ
The page says "No size sales data found" even though I have sales in this period.
A size shows as UNKNOWN in the chart.
My category doesn't match any of the five ideal-curve types listed in this article — what benchmark does it use?
The Category dropdown is empty until I run a report once.
Variance badges disappear when I uncheck "Show ideal curve".
🧑💻 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):
ProductProductVariantSaleSaleItem
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.