The Simulator That Makes Inventory Transfers Defensible
The Situation
Inventory Allocation Simulator is a planning console for distributors, retailers, and supply-chain operators that need to decide where scarce stock should sit before demand arrives.
Teams need it when warehouse stock, SKU economics, lead times, demand history, and transfer lanes live in separate files or systems, and the planner has to defend a transfer before anyone knows which demand scenario will happen. A normal spreadsheet can tell you what moved last week. It cannot explain why 30 units should move from one warehouse to another while preserving safety stock, service level, lane capacity, transfer cost, and margin.
The reference workload is not a toy import. The shipped benchmark covers 50 warehouses, two thousand SKUs, and 100 scenarios. That is the size where manual review stops being planning and becomes guesswork.
The Cost of Doing Nothing
A planner earning roughly €55K to €75K a year who spends even one day a week reconciling stock spreadsheets, demand exports, and lane constraints burns €11K to €15K a year in labor before a single wrong allocation is counted. The real cost is larger: stockout exposure, margin lost to emergency transfers, and decisions no one can audit after the data changes.
The dangerous failure is quiet. A warehouse appears to have low demand because it sold zero units during a stockout. A naive forecast reads that as weak demand and sends stock somewhere else. The simulator guards against that by adding lost sales back into demand and marking those periods as uncertain.
What I Built
I built a multi-tenant Julia planning system with a Genie operations console, PostgreSQL audit store, Redis-backed workers, DuckDB backtests, and a JuMP plus HiGHS allocation solver. Operators import warehouses, SKUs, inventory, demand history, and transfer lanes from CSV or API. Then they define a policy, start a simulation, and review recommendations with binding constraints, scenario sensitivity, accepted tradeoffs, confidence, and net value.
The part that mattered most was not the optimizer. It was the evidence boundary around the optimizer. A simulation freezes the planning inputs before worker processing starts. If a warehouse capacity or SKU margin changes after the run, the completed run still explains itself from the snapshot it actually used.
System Flow
Data Model
Architecture Layers
The Decision Log
| Decision | Alternative Rejected | Why |
|---|---|---|
| Julia with Genie | Python API plus separate solver service | The optimization core and web layer share one deployment artifact and one language boundary. |
| JuMP and HiGHS | Black-box forecast and allocation model | The product needs readable constraints, infeasibility messages, and solver status, not just a transfer number. |
| Frozen snapshots | Live table reads during completed-run detail | Audit evidence must survive later edits to warehouse, SKU, demand, lane, and policy data. |
| Stockout-adjusted demand | Observed sales only | Zero sales during unavailable inventory is a supply failure, not low demand. |
| Local notifications first | External hub as required delivery path | Core simulation and review must run when every ecosystem adapter is disabled. |
| Decision audit rows | Status updates only | Approvals, rejections, expiries, and exports need reason, user, and time evidence. |
Ecosystem Integration
The simulator can consume ETA freshness from the delivery tracking gateway, mirror high-value allocation and simulation events through the notification hub, and trigger approval workflows through the workflow automation engine. These are supporting systems, not hard dependencies. All integrations are feature-flagged: the system runs standalone with no ecosystem dependencies.
Results
The shipped acceptance run proved the reference workload: 50 warehouses, two thousand SKUs, and 100 demand scenarios completed in 17,928.4753 ms against a 10-minute p95 target and generated two thousand recommendations. The deterministic solver fixture produces a 30-unit transfer with a 30,900-cent net value and exposes the binding constraints the planner needs to trust it.
The browser smoke test covers setup, login, CSV import, simulation, and approval over real HTTP with PostgreSQL and Redis. The full Julia regression finished at 2,100 passing tests after the final secret-scan fix. The next scaling pressure is dense lane topology, not the audit model. If every warehouse can transfer every SKU to every other warehouse, the worker should partition by region or category before solving.