Migration log · entry 007 · August 2026

Two systems, one truth.

The riskiest phase of a migration isn’t the build. It’s the stretch where both systems are alive at once — and the only way to survive it is to be ruthless about which one is telling the truth.

Phase one of this migration replaces the web platform only. The legacy ERP — the system that runs purchasing, warehouse, accounting, all of it — stays exactly where it is, for a coexistence period we intend to keep short. That gives us one non-negotiable rule: until cutover day, the legacy ERP remains the system of record. The new store never argues with the boss. It can display, it can collect, it can enrich — but on any fact the ERP owns, the ERP wins.

Coexistence, then, is a traffic problem. Products, inventory, pricing, and order status flow from the ERP toward the store, keeping the shelves honest. Web orders and newly registered customers flow back the other way, because an order that only exists on a website doesn’t get picked, packed, or invoiced.

That return path hides my favorite decision of the whole sync design. The old website talked to the ERP through an intake pipeline — staging tables and stored procedures, decades of validation and business logic baked in. Instead of writing to the ERP’s tables directly, the new platform submits orders and customers through that same pipeline. As far as the ERP can tell, the new store is just the old website having a very good day. It’s our “use the built-ins first” principle applied to a forty-year-old stack: the safest integration is the one the system already trusts.

Coexistence data flows: the legacy ERP on the private office network remains system of record; the cloud store syncs both ways through monitored jobs office network — private cloud Legacy ERP system of record still the boss New platform the store customers see products · inventory · pricing · status web orders · new customers through the old site’s own intake pipeline Sync monitor every run recorded: read · matched · mismatched · failed One truth until cutover: on any fact the ERP owns, the ERP wins.
The coexistence map: goods-facing data flows in, commerce flows back, and every sync run leaves a record.

The cadence follows a pragmatic rule: invest in real-time only where the business feels it. Orders and new customers move promptly, because a stalled order is a stalled shipment. Inventory and status ride scheduled polls measured in minutes. Bulk data rides slower cycles. We deliberately did not build elaborate real-time machinery onto a system we’re retiring — gold-plating the past is how coexistence periods stop being short.

And because two live systems disagree the moment you stop watching them, nothing syncs unobserved. Every job runs under a monitor that records every execution: rows read, matched, mismatched, failed, and the exact error when something breaks. “Did the sync work?” is never a guess or a feeling — it’s a row in a table. Some jobs exist purely to validate: they compare the two systems and report mismatches, and on those jobs a mismatch isn’t an error, it’s a finding. One guard I’m particularly glad exists: a price of zero read from the legacy side is skipped and flagged, never written. A missing price is a problem; a free product is an incident.

One boundary shaped all of this: the legacy ERP lives on the office network, deliberately unreachable from the internet — and the new platform lives in the cloud. The first time anything cloud-side tried to dial the ERP directly, it couldn’t connect, and after sitting with the options we came to see that as the architecture talking, not failing. Punching a hole toward the internet into your ERP to serve a temporary bridge is a bad trade. So the flows run from the side that can see the ERP, and the monitor keeps the record. Security constraints you work with tend to age better than the clever ways around them.

Two systems, one truth, every exchange written down. That’s the whole coexistence strategy — and the day the sync stops being needed is the day this migration is finished.