Replacing a Spreadsheet-Run Manufacturing Plant
Production, purchasing and stock control had become dependent on linked spreadsheets maintained around an ageing accounts package. The replacement introduced controlled operational records without asking the plant to stop while the system changed underneath it.
- Engagement
- ERP replacement
- Duration
- Around nine months
- Team
- Engineers, a business analyst and a delivery lead

This account is anonymised. The client is described by sector rather than by name, and outcomes are described in words rather than figures — no percentage or saving is quoted because none can be independently evidenced here.
A production system assembled outside the system
The plant’s nominal system of record held customers, suppliers and financial postings, but the operational truth lived elsewhere. Production orders were copied into planning workbooks, material demand was recalculated by formulas and stock adjustments arrived after physical movements had taken place. Different sheets used different part identifiers, and a late engineering revision could be reflected in purchasing without reaching the traveller used on the floor. None of these practices was irrational in isolation. They were local responses to software that no longer represented how work moved through the plant. Together they made provenance difficult: a planner could explain a decision, but the records could not reconstruct it unaided.
Replacement could not begin with a blank database and a ceremonial cut-over. Open orders, partially completed assemblies, reserved material and supplier receipts had to retain their meaning while production continued. Some workstations had intermittent connectivity, labels needed to remain readable by existing equipment and finance required a stable bridge into the general ledger. The first task was therefore to define operational states and accounting boundaries, not to reproduce spreadsheet screens. The engagement treated migration, process design and software delivery as one body of work, with each release proving that a real manufacturing event could be recorded once and followed through planning, execution, inventory and finance.
What shaped the build
Continuous production
The legacy records could not be switched off until every open production and purchasing state had a tested destination.
Intermittent shop-floor connectivity
Operator workflows had to remain safe when a workstation lost its connection, without creating duplicate material issues or completions.
Mixed identifiers
Part, supplier and work-order references had accumulated aliases that could not simply be normalised without preserving their history.
Existing finance boundary
The accounts package remained authoritative for the ledger during transition, so operational postings needed an explicit, reconcilable interface.
How the engagement ran
- 01
Trace actual work
We followed representative orders from quotation through despatch, recording state changes, hand-offs, exceptions and the spreadsheets used to repair missing system behaviour.
- 02
Define records and controls
Part revisions, bills of material, routings, stock locations and production orders were modelled with ownership, permitted transitions and accounting consequences.
- 03
Build in operational slices
The platform was released by connected workflow, allowing planners and stores staff to exercise complete events rather than review isolated screens.
- 04
Rehearse migration
Repeatable imports produced reconciliation reports for master data, stock, open purchasing and work in progress before any record became authoritative.
- 05
Transfer control deliberately
Each spreadsheet was retired only after its decisions, exceptions and downstream outputs had an owned equivalent in the new process.
Model the manufacturing event, not the workbook
The workbook estate mixed master data, transactions, calculations and approvals in the same cells. Copying that structure would have preserved ambiguity behind a browser. The replacement separated effective-dated part revisions from bills of material, and bills from the production orders that consumed them. Routings described expected operations without rewriting orders already released against an earlier revision. A status model distinguished planned, released, in-progress, completed and closed work, with guarded transitions and an event history. Corrections were represented as compensating movements rather than edits to completed records. This made the sequence inspectable and prevented a retrospective spreadsheet change from silently altering what the plant had actually built.
Material requirements were generated from released demand and current supply, but recommendations remained recommendations until a planner accepted them. That distinction mattered because supplier constraints, substitutions and batch decisions contained judgement that no formula fully represented. Reservations linked stock to demand without pretending that physically unissued material had already been consumed. Issues, returns, scrap and completion each became explicit inventory movements with source references. The same movement ledger drove available stock and the finance export, removing the former gap between a planner’s balance and the valuation presented at close. Where units differed between purchasing, storage and production, conversions were governed against the item rather than embedded in individual formulas.
Design offline behaviour as a consistency problem
A shop-floor screen that merely displayed an error during a network interruption would have sent operators back to paper. The client application therefore retained the bounded information needed for the active operation and queued permitted observations locally. Each command carried a durable identifier, expected record version and operator context. On reconnection, the API could recognise a replay, reject a transition based on stale state or accept the event exactly once. Potential conflicts returned to a visible review queue; the client never resolved them by quietly choosing the latest timestamp. Work that affected allocation or traceability remained unavailable offline where a safe merge could not be defined.
This constraint changed interface design. Operators selected from the work already assigned to a station rather than searching an entire catalogue, and the screen made synchronisation state unambiguous. Label generation used server-issued identifiers, while local reprints preserved the original identity instead of creating another unit. Scanning validated part, revision and operation context before a movement was queued. The implementation favoured a small number of explicit commands over generic record editing because commands could express invariants such as preventing completion before required material declarations. Connectivity testing included interruption at each write boundary, repeated submission and an outdated assignment, not merely a demonstration after disconnecting a read-only page.
Treat migration as operational reconciliation
The spreadsheets could not be imported as if they shared one schema. Profiling exposed reused identifiers, descriptive variants, orphaned supplier references and formulas whose displayed value depended on unavailable linked files. A staging model retained source file, sheet, row and original value beside every proposed target record. Mapping rules were versioned and rerunnable, with unresolved values reported instead of coerced into defaults. Master data owners decided whether an apparent duplicate represented an alias, a revision or a genuinely distinct item. That decision trail was retained because later investigation often begins with the language used on an old purchase order or drawing.
Open transactions required event-level treatment. A purchase line partly received is not equivalent to a new line for its remaining quantity, and work in progress cannot be represented safely by importing only its current status. Rehearsals rebuilt opening stock by location and condition, established reservations, then loaded open purchasing and production against the same identifiers. Control reports compared source populations with staged and accepted records and exposed exclusions with reasons. Finance reviewed the opening valuation and the first operational posting batches as a bridge, not as unrelated totals. The cut-over plan consequently described which source could still change, when extraction occurred and who owned each difference, rather than relying on a final all-purpose import.
Make control visible in ordinary use
The platform did not reserve traceability for a specialist audit report. A planner could open a production order and follow its originating demand, revision, allocated material, floor observations, completions and stock consequences. Stores staff could see why stock was unavailable instead of overriding a balance, while purchasers could distinguish planned demand from an approved order. Role permissions followed operational authority: creating a part, approving a substitution and correcting a completed movement were separate capabilities. Sensitive changes required a reason and retained before-and-after values. This reduced dependence on informal knowledge without forcing every routine action through the same heavyweight approval path.
Operational reporting was built from the transaction model rather than a replicated set of spreadsheet calculations. Exception views showed shortages, stale reservations, receipts awaiting inspection and orders whose recorded state conflicted with expected progress. They linked back to the underlying events so the response could repair the source record instead of patching a report. The ledger interface followed the same principle. Posting batches were deterministic, traceable to movements and protected against duplicate export; rejection by finance produced an actionable state rather than an email attachment. The resulting system remained a set of bounded operational controls connected by identifiers and events, not a monolith that claimed to automate judgement it could not safely make.
What changed
- Production status stopped depending on which planning workbook had been opened most recently.
- Stock movements became traceable to purchasing, production or an authorised correction.
- Engineering revisions could change future work without rewriting the basis of released orders.
- Finance received operational postings through a repeatable reconciliation rather than spreadsheet journals.
- Offline work became an explicit synchronisation state instead of an unrecorded paper exception.
Stack
- React
- TypeScript
- Node.js
- PostgreSQL
- Redis
- Docker
Common questions
Can a manufacturing ERP be replaced without stopping production?
Yes, provided authority transfers by defined workflow rather than by one indiscriminate switch. Open-state migration, parallel reconciliation and rehearsed rollback conditions are essential parts of the delivery.
How do you migrate work in progress from spreadsheets?
Work in progress is reconstructed as linked operational state, not loaded as a single balance. Source lineage and reconciliation reports are retained so exclusions and transformations can be reviewed.
What happens when shop-floor devices lose connectivity?
Only operations with a safe offline contract are queued locally. Idempotent commands, record versions and visible conflict handling prevent reconnects from creating duplicate or silently reordered events.
Does the new system have to replace the finance package?
No. An operational platform can preserve an existing general ledger boundary through deterministic posting batches, control-account mapping and reconciliation back to source movements.
Describe your version of this.
The constraints are never identical, and that is usually where the interesting engineering is. Tell us what yours are.


