Skip to content

Forecasting that keeps shelves full, not overstocked

A demand-forecasting system that turns sales history, seasonality, and promotions into store-level reorder recommendations buyers can trust.

Forecast · week of 04/13
Every line's forecast against what sold, with its confidence band · store 014 · Riverside Park
High-velocity lines Week of 04/13/2026RM
Stockouts · high-velocity−41%Two quarters after rollout vs same two last year
Excess carrying cost−28%Within 90 days of launch
Forecasts inside their band90%Store-SKU-week, measured against actuals
Risk alerts · this store5Fired on projected cover, ~3 weeks out

Lines this week P10–P90 band Median Sold last week

11 of 212 lines · sorted by velocity
SKUCategoryForecastBandLast week · band vs soldSoldCoverStatus
LF-40217Solar path lights, 6-packOutdoor lighting3831–45403.6 wkIn band
LF-11820Raised bed kit, cedar 4×8Garden structures1410–18162.1 wkStockout risk
LF-22305Potting mix, 50 qtSoil & compost9682–1111091.8 wkStockout risk
LF-30744Hose reel cartWatering117–15514.2 wkOverstock
LF-40533String lights, 48 ftOutdoor lighting2721–34264.4 wkIn band
LF-51002Hanging basket, fuchsiaLive plants4233–52372.6 wkStockout risk
LF-60419Patio cushion, 20 inOutdoor living1812–25136.3 wkIn band
LF-11377Seed starter tray, 72-cellSeeds & starting2318–29283.9 wkIn band
LF-72210Bird feeder, copperWild birds63–9419.5 wkOverstock
LF-22871Mulch, cedar, 2 cu ftSoil & compost131112–1511243.3 wkIn band
LF-30192Oscillating sprinklerWatering1511–20164.8 wkIn band

LF-40217 · ten weeks, forecast against sold

9 of 10 weeks inside the band
03/16 · cold snapsold 19 · band 23–35

Replenishment ready

Solved 5:10 AM
11 linesPre-ticked · solved to supplier lead timesReview

What the engagement involved

Industry
E-commerce & Retail
Duration
13 weeks
Cooperation model
Time & materials
Services
Data engineeringForecast modelsBuyer tooling
Integrations
ShopifyStripeKlaviyoShipStation
Technologies
PythonFastAPIPandasScikit-LearnPostgreSQLReact
Team
1 Project lead1 Product designer1 Data engineer1 Analytics engineer1 Backend engineer1 QA engineer

Client name withheld under NDA. Engagement details are shown to the extent our agreement permits.

Introduction

The question we were asked

Buyers over-ordered slow movers and ran out of hits. We built forecasting that recommends what each store should reorder and when.

A chain of twenty-five stores whose buyers reordered from last month's sell-through, one category at a time, in a weekly meeting. Capital was the trigger: an inventory audit put a meaningful share of stock in lines that hadn't moved in two seasons, while the fastest sellers were out of stock somewhere every week. Both were the same fault seen from two ends.

Data & AI

What it settled

The decision, first

  1. 01

    Stockouts reduced by 41% across high-velocity product categories.

    Stockouts fell because the trigger moved from current stock to projected cover, which shifts the warning from the week of the problem to three weeks before it.

  2. 02

    Carrying cost of excess inventory dropped by 28% within 90 days of launch.

    The excess cleared because the same model run backwards flags lines that won't sell through by season end. Before, dead stock had never been identified, only discovered.

  3. 03

    Forecast model accuracy reached 90% across seasonal demand shifts.

    Accuracy is reported against the confidence band on purpose: a forecast that knows when it's unsure is what buyers were willing to act on.

What the numbers couldn't answer

Reorder decisions relied on last month's numbers, leaving popular items out of stock and capital tied up in dead inventory.

Reordering from last month's numbers means always ordering into the demand that has just passed. On seasonal lines that's precisely backwards, and the audit showed it: the dead stock was concentrated in items that had spiked once, been reordered on the spike, and arrived after it. Meanwhile lead times varied by supplier and were treated as a single average.

We built a pipeline unifying sales, seasonality, and promo calendars, trained per-store demand models, and gave buyers a reorder dashboard with confidence bands.

The solution

How we worked it through

  • Consolidated POS, promo, and seasonal signals into one feed

    Consolidation exposed the real obstacle: promotion dates were recorded inconsistently across the chain, and cleaning them took longer than the modelling.

  • Trained per-store, per-SKU demand models

    Models are fitted per store, not per chain, because the seasonal curves of a city-center branch and a retail park are genuinely different shapes.

  • Surfaced reorder recommendations with confidence ranges

    Reorder quantities solve against each supplier's real lead-time spread and minimum order quantity, so a recommendation is something a buyer can raise unchanged.

  • Piloted in ten stores before chain-wide rollout

    Ten stores ran for six weeks with buyers free to ignore every recommendation, and the gap between taken and ignored became the tuning signal.

Process

Phase by phase

  1. Phase 1: Data Pipeline & Feature Store

    POS & Seasonality Signal Consolidation

    Unified historical POS sales data, promotion calendars, and local holiday/weather signals into a normalized feature store.

    • Data Lake Architecture
    • Feature Store Pipeline
    • Historical Data Audit
  2. Phase 2: Predictive Demand Modeling

    Per-Store SKU Demand Engine

    Trained machine learning demand models per SKU and store location with probabilistic confidence intervals.

    • Demand Model Suite
    • Model Validation Report
    • Accuracy Benchmarks
  3. Phase 3: Buyer Dashboard & Workflow

    Reorder Cockpit & Purchasing API

    Designed a reorder dashboard that surfaces stockout risk warnings and recommended purchase orders, each approved by a buyer in one click.

    • Buyer Dashboard UI
    • Purchasing System API
    • Alerting Engine
  4. Phase 4: Store Pilot & Chain Deployment

    Staged Rollout & Inventory Audit

    Piloted in 10 store locations before rolling out chain-wide across all 25 retail stores, measuring stockout drops.

    • Pilot Performance Report
    • Chain Rollout Clearances
    • Inventory Impact Analysis
Feeds
The overnight feeds behind every forecast · 10 sources, when each last ran, and how fresh the data underneath is
Run all now Week of 04/13/2026RM

Sources

10 of 10 ran · last 4:52 AM
SourceSystemScheduleLast runRowsData as ofStatus
POS salesStore tills · 25 storesNightly2:10 AM184,302Yesterday closeRan
ReturnsStore tillsNightly2:14 AM3,918Yesterday closeRan
Inventory on handStock systemNightly2:40 AM5,3002:30 AM countRan
Open purchase ordersPurchasingNightly2:52 AM1,1462:45 AMRan
Promotion calendarMarketing plannerNightly3:05 AM412Normalized datesRan
Supplier lead timesReceiving logNightly3:20 AM9,874Per deliveryRan
Supplier MOQs & case packsVendor masterWeekly · Sun04/122,2101 dayRan
Store seasonal curvesAislecast modelsWeekly · Sun04/12251 dayRan
Local holidaysPublic calendarMonthly04/0186Through 12/31Ran
Weather, 7-dayForecast serviceNightly4:52 AM1754:30 AM runRan

One feature table

store_sku_week
Two years of sales, the promotion calendar and each store’s seasonal curve, joined into one row per store, per SKU, per week.
store_idskuweekunits_soldpromo_depthseason_indexholiday_flagweather_7dlead_time_p90
Promotion dates cleaned chain-wide before any model was fitted

Rollout by wave

25 stores
PPilot · 10 stores · 6 weeksBuyers free to ignore every recommendation
2Wave 2 · 8 stores · after the pilotTuned on the gap between taken and ignored
3Wave 3 · 7 stores · chain-wideAll 25 stores live
Stockouts compared quarter to quarter against the year before
On screen

The ten overnight feeds behind every forecast and when each last ran, the one store-SKU-week feature table they build, and the rollout from a ten-store pilot to all twenty-five stores by wave.

What it changed

−41%

Stockouts

−28%

Excess inventory

90%

Forecast accuracy

Stockouts and excess inventory compare the two quarters after rollout with the same two quarters the previous year, so seasonality is held constant. Forecast accuracy is measured at the store-SKU-week level against actuals, reported as the share of forecasts inside their own stated confidence band instead of as a point-estimate error.

Client name withheld under NDA. Figures are approximate, drawn from the engagement’s own reporting.

01

Store-Level Reorder Recommender

Generates purchase order quantities per store from lead times and demand forecasts.

Two years of sales, the promotional calendar and the store-level seasonality curves were unified into one feature table per store per SKU per week. Reorder quantities are solved against each supplier's actual lead time and minimum order quantity, never a global rule, so the recommendation is something a buyer can raise as a PO without adjusting it. Confidence bands travel with every number.

What shipped
  • Per-store, per-SKU weekly feature table
  • Solved against real supplier lead times and MOQs
  • Confidence bands attached to every recommended quantity
Replenishment · week of 04/13
Recommended order quantities solved against each supplier's lead-time spread and minimum order
Export POs Week of 04/13/2026RM
Store014 · Riverside Park
Lines recommended11 of 13
Order value$6,850.20
Solved againstLead-time spread + MOQ

Recommended orders

Pre-ticked · untick to leave a line out
SKUSupplier · leadMOQ / packBand 4 wkOrderValue
Solar path lights, 6-packNorthgate Outdoor · 12–21d48 / 1221460$504.00
Potting mix, 50 qtBrookhollow Soils · 3–5d60 / 60420240$1,740.00
Raised bed kit, cedar 4×8Cedarline Works · 18–30d6 / 25824$1,536.00
Mulch, cedar, 2 cu ftBrookhollow Soils · 3–5d120 / 60560180$711.00
String lights, 48 ftNorthgate Outdoor · 12–21d24 / 611836$604.80
Hanging basket, fuchsiaFernway Growers · 2–4d12 / 129648$552.00
Tomato plant, 1 galFernway Growers · 2–4d24 / 1213272$244.80
Patio cushion, 20 inHarbor Loom · 21–35d12 / 67424$340.80
Solar lantern, amberNorthgate Outdoor · 12–21d24 / 126624$295.20
Oscillating sprinklerRainpath Irrigation · 10–16d12 / 66218$172.80
Seed starter tray, 72-cellTillman Supply · 7–10d24 / 248448$148.80
Hose reel cartRainpath Irrigation · 10–16d6 / 222—Covered
Bird feeder, copperWrenfield Goods · 14–20d6 / 620—Covered
11 lines ticked · $6,850.20 · raised as POs per supplierHold weekApprove week

Why 60 units

LF-40217
Solar path lights, 6-packNorthgate Outdoor Supply · case of 12 · MOQ 48
Next 28 days · per week148–214
04/1304/2004/2705/04
Top of band, 4 weeks · P90214
Median, for reference181
On hand− 128
On order · arrives 04/16− 36
Short of the band50
Up to whole cases · 5 × 1260
At least MOQ 48Met
Supplier lead time · last 12 deliveries12–21 days
60 units · $504.00Band ± travels with the PO
On screen

Replenishment for one store: recommended quantities and their value, pre-ticked so a buyer approves the week in one pass, with one line opened to show the order solved from the top of its band, the supplier's lead-time spread, the case pack and the MOQ.

Risk queue
Stockouts and overstocks across stores, ordered by days left before the line breaks · fired on projected cover
All categories Week of 04/13/2026RM
Stockout risk9 lines
Overstock risk5 lines
Earliest break04/18 · 5 days
Fires onProjected cover < 21 days

Open alerts · all stores

14 open · 2 more overstock below
RiskSKUStoreOn handProjected coverLands · leftAction that avoids it
StockoutPotting mix, 50 qtLF-22305031 · Mill Street4404/18 · 5dRaise PO for 120 today · supplier ships in 3–5 days
StockoutRaised bed kit, cedar 4×8LF-11820014 · Riverside Park1204/22 · 9dTransfer 6 from 008 · order 24 for the week after
StockoutString lights, 48 ftLF-40533022 · Harbor Point3104/25 · 12dOrder 36 by 04/14 · lead time runs to 21 days
StockoutHanging basket, fuchsiaLF-51002008 · Oak Hollow4004/27 · 14dOrder 48 · yard event uplift lands that week
StockoutSolar path lights, 6-packLF-40217019 · Canal Row5804/30 · 17dOrder 48 by 04/16 to land before the gap
StockoutSeed starter tray, 72-cellLF-11377003 · Westgate2605/01 · 18dOrder 48 · or transfer 24 from 014
StockoutMulch, cedar, 2 cu ftLF-22871014 · Riverside Park19005/02 · 19dOrder 180 in next week's run
StockoutOscillating sprinklerLF-30192031 · Mill Street1905/03 · 20dOrder 18 in next week's run
StockoutTomato plant, 1 galLF-51190022 · Harbor Point4405/03 · 20dOrder 72 · grower ships in 2–4 days
OverstockBird feeder, copperLF-72210014 · Riverside Park11708/29 · 138dStop reorders · 79 left at season end · transfer 30 to 003
OverstockHose reel cartLF-30744014 · Riverside Park6408/29 · 138dCancel open PO for 12 · 21 left at season end
OverstockWind chime, bambooLF-60877019 · Canal Row5208/29 · 138dMove to endcap · no reorder · 26 left at season end
21-day warning lineOverstock: forecast demand won't clear the units before season end
On screen

The risk queue across stores, ordered by days left before the line breaks: alerts fired on projected cover, each naming the SKU, the store, the date the trouble lands and the action that avoids it, with dead stock flagged at season end.

02

Stockout & Overstock Risk Alerts

Early warnings for imminent stockouts and building dead stock.

Alerts fire on projected cover instead of current stock, which moves the warning from the week of the stockout to three weeks before it. Dead stock is flagged by the same model running the other way: units whose forecast demand won't clear them before the season ends. Each alert names the SKU, the store, the date the trouble lands and the action that avoids it.

What shipped
  • Fires on projected cover, not on today's stock level
  • Same model run in reverse to flag dead stock
  • Every alert names the date and the action that avoids it
Promotions · spring plan
8 spring promotions modelled · baseline, expected uplift and the extra units each one needs ordered in
Stage promotion Week of 04/13/2026RM

Spring promotions

Chain · units across participating stores
PromotionDatesDepthStoresBaselineUpliftExtra units
Spring yard event04/24–04/3020%254,180+31%+1,296
Raised bed weekend05/01–05/0315%12620+24%+149
Tomato & herb starts05/01–05/1410%253,600+12%+432
Mother's Day baskets05/04–05/10Buy 2252,310+42%+970
Mulch 5 for $1505/08–05/17Bundle256,940+18%+1,249
Patio refresh05/15–05/2525%181,480+27%+400
Memorial Day lighting05/22–05/2530%252,050+46%+943
Watering week06/05–06/1120%15910+21%+191
Extra units = baseline × expected uplift+5,630 units to order in

Where +31% comes from · Spring yard event

Comparable past promotions
Spring yard event 202520% · 7 days · 25 stores · actual sell-through+29%
Spring yard event 202415% · 7 days · 22 stores · actual sell-through+24%
Memorial Day outdoor 202520% · 4 days · 25 stores · actual sell-through+35%
Estimate +31% · weighted by depth, length and storesFrom how comparable promotions actually performed, not a flat multiplier

Scenarios side by side

Spring yard event
Stores25
SKUs18
Starts04/24
Scenario AChosen20% · 7 days
Baseline units4,180Expected uplift+31%Extra units+1,296Extra stock value$11,860Left at season end0 lines
Scenario B30% · 10 days
Baseline units5,970Expected uplift+44%Extra units+2,627Extra stock value$24,040Left at season end3 lines
Scenario A recorded as shippedActuals feed next spring’s forecastCommit A
03

Promotion Impact Simulator

On screen

Eight spring promotions modeled with baseline, expected uplift and the extra units each needs ordered in; the uplift traced to comparable past promotions, and two scenarios compared side by side before one is committed.

Simulates inventory requirements for upcoming marketing campaigns and seasonal sales.

Buyers can stage a promotion (depth, duration, stores, SKUs) and see the inventory it would require before committing to it, with the uplift estimated from how comparable promotions actually performed instead of a flat multiplier. Scenarios are saved and comparable side by side, and the one that ships is recorded so the following year's forecast learns from what really happened.

What shipped
  • Uplift estimated from comparable past promotions
  • Scenarios saved and comparable side by side
  • The chosen scenario recorded and fed back into next year

How the engagement ran

01
  1. 01

    A cross-functional team of 6 worked on a time & materials basis over 13 weeks, covering Data engineering, Forecast models, Buyer tooling. We ran two-week increments, each one shippable, reviewed live before it merged. Decisions were recorded as they were made, so the reasoning survived the people who made it.

    Ten stores piloted for six weeks before anything went chain-wide, with buyers free to ignore every recommendation, and the gap between what they ignored and what they took became the tuning signal. Time and materials suited a project whose modeling scope genuinely couldn't be fixed until the data quality was known.

One SKU, one week

Why the order is 60, and why last month’s rule said zero

One spring line at one store, worked through: the forecast as a range, how earlier ranges held up against what sold, and the quantity solved from the top of the band against the supplier’s lead time and case pack. Switch tabs, or use the arrow keys once one is focused.

Solar path lights, 6-pack · store 014 · Riverside ParkLF-40217 · Outdoor lighting
Next 28 days · units per weekMedian 181 · band 148–214
wk 04/13
wk 04/20
wk 04/27
wk 05/04
P10–P90 band Median Promotion week
Where the median comes from
Same weeks, two years of sales150
Store 014 seasonal curve+19
Spring yard event, 04/27+12

The forecast is a range, not a number. Store 014 is a retail-park branch, so it uses its own seasonal curve instead of the chain's, and the yard event on 04/27 widens that week's band upward. The buyer sees the band before any quantity.

Architecture

From last night's register data to this morning's purchase order

Built in Python with FastAPI, Pandas and Scikit-Learn over PostgreSQL, with a React cockpit for buyers. The confidence band is computed at the model and carried unchanged to the screen where the order is approved.

  1. 01 · Source
    POS, promotions, seasonalityRegister sales, the promotion calendar and local holiday and weather signals arrive as one feed, with promotion dates cleaned chain-wide before any model sees them.
  2. 02 · Feature store
    Store-SKU-week tableTwo years of sales normalized into one row per store, per SKU, per week, so every model reads the same history.
  3. 03 · Engine
    Per-store demand modelsFitted per store, not per chain, because a city-center branch and a retail park have different seasonal shapes. Every forecast carries a confidence band.
  4. 04 · Solve & alert
    Reorder solver + risk engineQuantities solved against each supplier's real lead-time spread and MOQ; alerts fire on projected cover, and the same model run in reverse flags dead stock.
  5. 05 · Deliver
    Buyer cockpit + purchasing APIRecommendations arrive pre-ticked with their bands for one-click approval, and approved orders go to the purchasing system through its API.
Before a buyer commits stock

Stated uncertainty, real lead times, human approval

Every quantity says how sure it is

Confidence bands travel with every recommended quantity, and accuracy is reported as the share of forecasts landing inside their own stated band, so an unsure forecast says so before capital is committed.

Solved against the real supplier

Each order is solved against that supplier's actual lead-time spread and minimum order quantity instead of a single average, so the recommendation can be raised as a PO without being adjusted.

The buyer keeps the decision

Ten stores ran for six weeks with buyers free to ignore every recommendation before anything went chain-wide, and the gap between what was taken and what was ignored became the tuning signal.

Are your buyers still reordering from last month’s numbers? Scope your build in 3 minutes.

Scope your build
Have a project?

Let's talk

Running a large platform, shaping a first MVP, or getting a product ready for a funding round? Tell us where you are. We'll shape the process around it, and stay with you after launch.