Internal operations platform
Warehouse Inventory
and Fulfilment System
Multi-app inventory, shelfing and order-return system for a multi-channel retail warehouse.
A warehouse management system running a live fulfilment operation: barcode-led picking, packing, shelfing and refiling, labour budgeting against real payroll periods, and a customer support desk - on a .NET 9 API with four front ends.
- Orders processed
- 7M+
- Products tracked
- 64K+
- Physical boxes
- 9,300+
- Staff on tasks
- 68
Live since 2022
Every shift, every day
01Summary
An internal platform that tracks every unit of stock in a real, physical warehouse — from the moment it is scanned in, through the exact box and shelf it sits in, to the moment it is picked, packed, shipped, or returned and put back into circulation. It is live production infrastructure a warehouse floor runs on every shift, and the figures below come straight from the production database.
- Accurate stock counts
- Barcode-driven workflows
- Clean audit trail

02The Problem
Running the warehouse side of a multi-channel retail business means reconciling three things that constantly drift apart: what the system thinks is in stock, what is physically on a shelf, and what a customer is actually owed.
Stock arrives for different reasons — matched to a purchase order, unmatched free stock, count corrections or customer returns — but it all has to land in the same inventory count without the reasons bleeding into each other.
Every unit counted in stock has to map to a real box, in a real storage bay, on a real floor, or a picker has no way to find it.
Some products live one-per-box on open shelving; others are stored several-to-a-box on pallets, so one "is this box taken" rule cannot serve both.
Picking, shelving and refiling are separate steps that all have to agree, or staff double-pick stock that is already spoken for.
Returns must feed the same pipeline as new stock without ever making the system believe an unrelated customer's order was just fulfilled.
03My Role & Scope
End-to-end development, from architecture to deployment and ongoing production support.
- Inventory & stock-in pipelineOne shared endpoint handles four stock-in reasons — Order Receive, Quantity Adjustment, Free Stock and Return — each opting into different downstream behaviour instead of forking into separate code paths.
- Physical location modellingThe floor → storage location → box → product hierarchy, with rules that differ by storage type: Regular (one product per box) versus Bulk and Pallet (several products sharing a box).
- Order fulfilment workflowsShelfing, Collection (FIFO off the oldest collection sheet), Refiling and location-scoped variants of each, all driven by barcode scans on the floor.
- Returns moduleBuilt end to end: search by tracking number, order number or Amazon/eBay order ID, restock through the same pipeline, log unmatched items for follow-up and raise support tickets.
- Staff operations toolingTask management across 95 task types, task-gating so pages refuse product data unless the operator's running task matches, and payroll-linked budget-vs-actual hours.
- Customer support platformA separate Next.js app for the full support-ticket lifecycle, sharing a login session with the warehouse app.
04Architecture
Every app reads and writes the same database through EF Core, with no queue between modules — so correctness depends on every write path agreeing on what a box, a collection or a stock-in reason is allowed to do. 4.4M+ inventory-audit rows and 690K+ scan-in events have built up since 2022.
Warehouse floor input
Legacy frontend
ASP.NET Core Web API + EF Core
SQL Server
05Key Features
Everything the platform does, in one place.
- Multi-reason stock-in pipelineFour stock-in reasons through one endpoint, each explicitly opting in or out of every downstream behaviour so new reasons cannot quietly drift.
- Storage-type-aware box rulesRegular boxes hold exactly one product; Bulk and Pallet boxes deliberately share. Regular-only checks apply only to Regular storage.
- Task-gated barcode workflowsShelfing, Collection and Refiling check the operator's own running task before showing any product data.
- Order return moduleSearch or scan, restock through the shared pipeline, decrement delivered quantity and raise a support ticket with a mandatory sub-issue type.
- Staff task budgeting95 task types, live running-task tracking across 68 staff and a monthly budget-vs-actual-hours view tied to payroll rates.
- Customer support ticketingCreate, reopen, close and reassign issues with attachments, against the same order and product data.
06Engineering challenges & how I solved them
Real problems found against live production data — with the actual debugging path, not just the fix.
A new stock-in reason silently marked a stranger's order as fulfilled+
Symptom: After adding a Return reason to the shared stock-in pipeline, a returned product's Shelfing page showed 1 unit of "Collected Stock" that nobody had collected.
Investigation: Traced every row the request touched by timestamp. The return had passed through a helper written for genuine purchase-order stock, which auto-fulfils any pending order waiting on that product — so an uninspected return had completed an unrelated customer's order.
Fix: Gated the helper to skip the Return reason while the other three reasons keep using it, and verified by diffing the production database's exact before-and-after state.
Full-entity reads on legacy tables were one bad row from a 500+
Symptom: A SqlNullValueException buried in a generic 500 on an arbitrary-looking subset of order and product lookups.
Investigation: EF Core maps non-nullable columns straight off the schema, but years of legacy rows held NULLs in exactly those columns. Loading the full 60-column entity meant one unrelated NULL could take down the whole request.
Fix: Replaced full-entity loads with explicit .Select() projections on every hot path, so a NULL nobody reads can no longer sink a request.
A rule meant for one storage type was blocking another+
Symptom: Reserving a bulk box for a second product failed with "box already in use", even though bulk boxes are meant to hold several products.
Investigation: A leftover zero-quantity, unreserved stock row from a previous product was being counted as occupying the box for every storage type, not just Regular.
Fix: Scoped the cross-product block to Regular boxes and ignored empty leftover rows — recovering capacity Bulk and Pallet storage had been silently losing.
A "broken" redesign was really a CSS build limitation+
Symptom: A redesigned page rendered with several colours and sizes simply missing, with no console error.
Investigation: The app loads a precompiled Tailwind v2 CDN build; any class outside that fixed file does nothing. Downloading and grepping the CSS confirmed only eight base colours existed.
Fix: Remapped every class to the supported set, swapped arbitrary values for presets or inline styles, and re-checked by grepping the diff rather than trusting the eye.
One endpoint, two pages, an audit log that could not tell them apart+
Symptom: Transfers made from the Refiling page appeared in the audit log as "Shelfing".
Investigation: Both pages share one transfer endpoint by design, but the log call had the page name hard-coded from whichever page was built first.
Fix: Added an explicit page-name field threaded from both frontends into the shared log, keeping the old value only as a fallback.
Case study
A new stock-in reason silently marked a stranger's order as fulfilled
Problem
After adding a Return reason to the shared stock-in pipeline, a returned product's Shelfing page showed 1 unit of "Collected Stock" that nobody had collected.
Investigation
Traced every row the request touched by timestamp. The return had passed through a helper written for genuine purchase-order stock, which auto-fulfils any pending order waiting on that product — so an uninspected return had completed an unrelated customer's order.
Solution
Gated the helper to skip the Return reason while the other three reasons keep using it, and verified by diffing the production database's exact before-and-after state.
07Impact
What changed once the platform was in place.
- Orders processed
- 7M+
- Products tracked
- 64K+
- Physical boxes
- 9,300+
- Staff on tasks
- 68
- Kept stock counts trustworthy across 7M+ historical orders and 4.4M+ audit records.
- Closed a data-integrity leak where a return could mark a stranger's order fulfilled — caught, root-caused and fixed against live data in one pass.
- Recovered box capacity Bulk and Pallet storage had been losing to stale data, without weakening Regular storage's one-product rule.
- Turned a page that looked badly designed into a documented build constraint the whole team can check for.
- Gave the audit log the ability to tell which of two pages performed an identical operation.
ASP.NET CoreEF CoreSQL ServerREST API designVanilla JSNext.jsProduction debuggingBusiness-rule modellingRole-based access controlShared-session authWorkforce tooling
Have a similar project?
Let's build something great together.
From shipping platforms to custom business tools — I can help turn your idea into reality.
- Free consultation
- Clear roadmap
- On-time delivery

