The situation
The business sells across three consumer websites, supported by a retail shop and a warehouse operation split across two buildings. Behind all of it sits an ERP running on SQL Server 2008: 1.46 million order headers, 2.5 million order lines, a catalogue of more than twenty thousand active products, and 8.9 million stock movements recorded continuously since 2006. It is the financial and stock record of the business, it is licensed and stable, and it is correct.
Nothing about it was failing. That was the difficulty.
Why the existing approach was limiting
The ERP worked, so there was never a moment that forced a decision — only a growing sense that the software had become the ceiling. Every new idea arrived at the same question, and the answer was always some version of *not with this*.
Its schema predates the conventions modern software assumes: fixed-width character columns padded with spaces, five-column composite keys, no foreign-key discipline, and business meaning encoded in bare numeric status codes. Every update has to hand-increment a single-character replication version column, or the change is silently lost between servers. Current PHP cannot complete a handshake with the database at all without being explicitly told to stop trying. None of that makes the ERP wrong. It makes it immovable — and it makes every new system built against it an act of archaeology first.
Around that core, operational software had accreted for years. The shop ran a legacy EPOS with its own second instance of the ERP, kept in step by eight ETL packages. A stock process written in VBScript ran on a single Windows PC and printed its tickets through WordPad. A standalone stock-transfer application duplicated authentication, database access and business rules that already existed elsewhere. Picking and dispatch lived partly in software and partly on paper.
The failures this produced were quiet ones. The stock-transfer application never incremented the replication version, so some of its writes were never seen by the second server. It populated roughly a third of the columns the ERP's own reporting expected. The VBScript process booked items out of shop stock hours or days after they had physically moved, leaving the system confidently reporting stock that was already in a crate somewhere else. The returns process left 9,128 records permanently stranded in an in-flight state. None of it produced an error message. It produced slightly wrong numbers, indefinitely.
Signal North's role
We took a strangler-fig approach rather than an ERP replacement: leave the ledger where it is, move operations off it one function at a time, and turn the eventual decommission into a decision the business can take calmly rather than a risk it has to survive.
That meant reconstruction before construction. Almost nothing about the ERP's real behaviour was written down, so we established it empirically against the live database and documented it — a schema and process reference covering thirty tables, the atomic stock-movement transaction, the status codes, the padding and versioning rules, and every trap we had proved was real rather than assumed. That document is now mandatory reading for any code in the estate that touches the ERP, ours or anyone else's.
Then four platforms, delivered inside twelve months by a small senior team: a unified warehouse platform across three applications covering picking, dispatch, stock transfer and warehouse tools; EPOS middleware replacing the legacy till system; a customer returns platform serving all three brands, built in sixty-six days; and a bridge carrying orders, shipments and refunds between the websites and the ERP.
Key decisions and intervention
- treat the ERP as the ledger, not the platform — new systems read and write to it deliberately, and never live inside it;
- reconstruct and document its real behaviour before writing code against it, and make that document a precondition of the work rather than a by-product;
- enforce read-only access inside the database driver itself, so an accidental write is blocked and alarmed rather than merely discouraged;
- restrict every write to a small number of named services sharing one transaction boundary, so stock can never half-move;
- match the legacy behaviour exactly where it was right, and correct it explicitly where it was silently wrong — the replication version, the missing columns, the deferred stock issue;
- design compensating transactions for the failure modes the old process left behind, so no new record can join the 9,128 already stranded;
- design for the scanner in someone's hand, not the screen on a desk — the handhelds, label printers and thermal ticket printers were in scope from the start;
- retire the periphery rather than the core — the second ERP instance, the eight ETL packages, the VBScript job and the standalone transfer application are all gone;
- carry around six thousand automated tests as the safety mechanism, because a system of record with two decades of history offers no room to find out in production.
What changed
Between ten and fifteen warehouse staff now work from handheld scanners on a platform built for the job, and pick errors have fallen by more than eighty per cent. Stock that used to be booked out days after it physically moved is booked at the moment someone scans it. Returns run end to end across three brands, where previously they were manual. Orders taken in the shop reach the ERP indistinguishable from the records they replaced.
The ERP still holds the ledger, and for now that remains the right place for it. But it is now surrounded by systems that are documented, tested and owned, rather than by scripts on a single Windows PC. The ceiling has gone: the business can add a brand, a warehouse process or a sales channel without first asking whether the ERP will allow it. Retiring it has moved from something that could not be contemplated to something the business has decided to do — and can schedule when the operation suits, rather than when a system finally fails.