Articles
Two systems, one customer: who owns the record
When two systems both accept edits to the same customer, both look right and neither is. How to assign an owner per record, and what a sync must answer.
- integration
- data
- operations
One system should own each record and the other should read it. When two systems both accept edits to the same customer, each is right on its own screen and neither is right for the business: a sync copies a disagreement rather than settling it. The answer flips only when two groups genuinely create the same kind of record at the same time and neither can be stopped — and even then, ownership is decided per field before anyone writes the integration.
What happens when both systems are right?
They usually are, inside their own boundary. The shop application holds the mobile number the customer actually answers. The accounting package holds the legal name and the credit limit that finance approved. Neither is wrong. The trouble starts with a question that spans both: how much may this customer buy on credit, and which number do we call when the delivery is refused?
At that moment one answer has to win. When both are available, the person at the counter picks whichever suits the sale. That is not a training problem. It is a missing decision.
Who should own each record?
The owner is the system where the record is created and where the consequence of it being wrong lands. Not the newest system, not the more expensive one, and not the manager's favourite.
| Record | Owner | Other side |
|---|---|---|
| Customer identity | CRM | Reads, never edits |
| Credit limit | Accounting | Reads before a sale |
| Stock quantity | Warehouse ledger | Reads, requests a transfer |
| Price list | Commerce | Reads, keeps a copy |
Ownership is per field, not per system. One system can own a customer's legal name and another the delivery address, and that is a good arrangement as long as somebody wrote it down. The fields nobody owns are the ones that drift.
Keep it next to the schema, versioned with the code; an ownership matrix in a slide deck is a rumour by the second month.
Is one-way sync enough, or do you need two-way?
One-way is a design; two-way is a negotiation running at machine speed. Prefer one direction per field.
Two-way sync is justified when two groups create records of the same type independently — a counter registering walk-in customers and a call centre registering phone customers, both live, neither able to wait. Even then, the three questions below must be answered before any code.
Field-level "last write wins" is not a rule, it is a decision to lose data quietly. If you cannot name the winner, send the conflict to a queue that a person clears. Slow and visible beats fast and silent.
Why do duplicates appear even when the sync works?
Because identity is a guess. The same customer appears as three spellings of one name and two mobile numbers, one of them a brother's. Matching those rows is string comparison, and string comparison fails exactly where it matters.
The fix is not a better matching algorithm. It is an identifier assigned at creation, in the owning system, carried everywhere else as a reference. Names change; identifiers do not. Once one exists, a duplicate is detectable instead of arguable, and provenance — which system produced a value, and when — becomes inspectable. The W3C Data on the Web Best Practices treat identifier stability and versioning as part of publishing data at all, which is the right seriousness for a customer record.
What happens when a sync fails mid-flight?
Half a record is worse than no record. An order is created on one side and the invoice is not; the retry then creates the order twice. The business now has a duplicate sale and a missing invoice, and both look like staff error.
Three mechanisms prevent most of it:
- Write the intent in the same transaction as the record. A queue of things to send, written atomically with the thing itself, so a crash cannot produce a record with no message, or a message with no record.
- Make the receiver idempotent. Every message carries an identifier, and receiving it twice changes nothing. Without this, every retry is a duplicate waiting to be discovered.
- Reconcile on a count, daily. For each record type, one number that must match on both sides. Not a dashboard — a check that fails loudly.
The failure to design against is silence. A queue that has stopped looks exactly like a queue with nothing to do, and the first person to notice is usually a customer.
Why is "we'll sync them" not a design?
Because it names a mechanism and skips three questions: which side wins, what happens to a record created on the losing side, and who is called when the link stops. An integration built without those answers works in the demonstration and is bypassed within a month.
There is a reliable test: ask the person who runs the process what they do when the two systems disagree. If the answer is "I know which one to trust", the decision exists, in one head instead of in the software.
What order do you do this in?
- List the record types that cross the boundary. Customer, product, price, order, invoice, stock.
- For each, name where it is created and where the cost of being wrong lands. That system owns it.
- Build the field table and mark the fields with no owner. Those explain most of the current mess.
- Choose a direction per field. Most need one; a few need a conflict queue instead.
- Decide the failure rule and the person who is told, before any code. A named person, not a channel.
- Add a daily reconciliation count per record type: one number equal on both sides.
- Build the sync, then delete the manual export. If the export survives, the sync is not trusted yet.
Where this goes wrong
- The owner becomes the system that is easiest to edit. Convenience wins quietly, and within a quarter the read-only side is the one everyone updates.
- Two-way sync is chosen "just in case". The conflict rule then defaults to whoever saved last.
- The integration is treated as a project, not a service. No monitoring, no owner after launch, and the first outage is diagnosed by whoever notices the numbers are odd.
- The phone number is used as the identifier. It is shared inside a family, it changes, and it is typed with different prefixes.
What this does not cover
It does not tell you which product to keep or which vendor to drop, or cover migrating history between the two systems, which is a discipline of its own. And it assumes you can change the behaviour of at least one side: when both are closed packages, ownership may have to be a nightly read-only copy — a weaker design, but still a decision.
We build the seam between systems you already own: an owner per record, one direction per field, and a failure that announces itself instead of waiting to be found.
Services in this article
Projects in this article
Articles
Related articles.
Why your stock count never matches the system
Counts drift because two places accept stock movements and neither owns the number. What to record, what to count, and what to fix first.
- inventory
- erp
- operations
Moving a spreadsheet into a real system without losing the numbers
The spreadsheet is the specification. How to read the rules out of the file, clean it, reconcile control totals, and stop the old sheet changing.
- migration
- data
- spreadsheets
Why nobody opens the dashboard you paid for
A dashboard is a routine, not a screen: one decision per panel, a named owner per number, and ten minutes a week that keep it alive.
- dashboards
- analytics
- reporting
Start a project
Have something to build?
One short brief is enough. You get a written scope and a fixed quote before anything starts.
