Healthcare & Life Sciences

Case study · Illustrative scenario

Migrating Business-Critical Data Without Losing Context or Relationships

A consolidation where two legacy systems had each modelled the same idea differently for two decades, and the mapping spreadsheet was the only artefact anybody had produced.

An articulated whale skeleton suspended in a museum hall above visitorsHealthcare & Life Sciences
ArchitectureExtraction to cutover

The migration path runs in five stages. Extraction and profiling read what the source systems actually hold rather than what the documentation says they hold. Mapping and transformation then record a decision for every field and every value, including the fields deliberately left behind. Loading follows a designed order so a parent always exists before the child that points at it, and every object carries a unique external ID so the load is an upsert that can be re-run safely. Reconciliation compares the result against the source using assertions written before the load, and produces a report a person who did not run the migration can check. Cutover runs the rehearsed sequence with a timed fallback and a named decision-maker.

  1. Extract and profile

    • Legacy system A extract
    • Legacy system B extract
    • Value distribution profile
    • Field completeness profile
    • Out-of-scope field register

    Reads the real distribution of values, which is how you find that a field described as mandatory is empty across the historic records.

  2. Map and transform

    • Field mapping
    • Value mapping per picklist
    • Definition reconciliation
    • Deduplication and match queue
    • Archive boundary

    Every value gets a decision, and the values that are collapsed or dropped are recorded rather than absorbed.

  3. Load in order

    • External ID per source system
    • Parent-first load order
    • Junction records after both parents
    • Second pass for circular references
    • Automation suspended

    Order is designed. A child loaded before its parent is a broken reference nobody notices for months.

  4. Reconcile

    • Reconciliation report
    • Key-for-key coverage check
    • Children-per-parent counts
    • Value distribution comparison
    • Named-record read-through

    Proves the migration rather than asserting it, and leaves an artefact that stands as evidence afterwards.

  5. Cutover

    • Full-volume rehearsal
    • Point of no return
    • Named decision-maker
    • Timed fallback
    • Archive retained and indexed

    A migration that has not been practised is a plan. Two consecutive identical rehearsals make it a procedure.

A worked scenario showing how we approach this problem. The architecture and decisions are our real practice; it is not an account of one named customer.

The problem, as it actually presented

The brief in this situation is almost always "we need to move the data across". It arrives as a spreadsheet, one tab per object, source field in the left column and target field in the right, with a date by which the legacy systems are meant to be switched off.

The spreadsheet is not wrong. It answers a much smaller question than the one that decides whether the migration succeeds.

A provider consolidating two legacy systems across twenty years of service records does not have twenty years of rows. It has twenty years of decisions. A status value meant one thing before a reorganisation and something different afterwards. A free-text note has been carrying the referral source since the day somebody discovered there was no field for it. A person exists twice because the two systems came from two organisations that merged, and nobody has ever had to reconcile them, because the systems never spoke to each other.

Moving the rows is the mechanical part. Moving the meaning is the engagement.

Why a field-to-field mapping is not a migration plan

A mapping says where a value lands. It does not say what the value means on arrival, and the gap between those two things is where migrations quietly fail.

Three failures recur.

The same idea, modelled differently. Both systems hold something called a case. In one it opens when the referral is received and closes when the episode ends. In the other it opens when the first appointment is booked, and a separate one is created for each service line. Mapped field to field, both become the same object, and every duration, count and trend computed afterwards mixes two definitions. The report runs. The number is meaningless.

Precision invented on the way in. A source system stores a date with no time, because the process never captured one. The target field is a date-time. Something has to supply the missing part, and if nobody decides, the load supplies midnight in whatever timezone the running user happens to have. Two decades of records then carry a precision that was never collected and a timezone nobody chose.

Values that lost their vocabulary. Picklists accumulate. A status list edited for twenty years holds live values, retired values, values differing only in punctuation, and values that were once a workaround for a missing field. A mapping that transfers them all preserves the mess and hard-codes it into the new automation. A mapping that collapses them silently destroys a distinction somebody will ask about.

What closes this gap is profiling before mapping: reading the actual distribution of values in the source rather than the documented one. It is unglamorous, it takes longer than anyone budgets, and it is the only way to discover that a field described as mandatory is empty across most of the historic records.

Relationships, and the reference nobody notices is broken

Rows have order. This is the genuinely mechanical part of a migration, and it still goes wrong more often than anything else.

A child loaded before its parent has nowhere to point. Depending on how the load is written, one of two things happens. The load fails loudly, which is fine. Or the reference is left empty and the record is created anyway, which is not. An empty lookup on a service record raises no alarm. It surfaces months later, when somebody notices a person with no history, or a report whose totals are smaller than everyone remembers them being.

So load order is designed rather than discovered. Accounts before contacts, contacts before cases, cases before the activities and files that hang from them, and every junction record after both of the things it joins. Where a relationship is circular, one side is loaded with the reference empty and a second pass populates it, and that second pass is a named step with its own reconciliation rather than a clean-up somebody is expected to remember.

The harder version of the problem is the relationship that exists in the source only as a convention. A note saying to see the record for the next of kin is a relationship. A reference number typed by hand into a text field is a relationship. These are real, they are not modelled, and the choice is either to reconstruct them, which is a judgement exercise with a review queue attached, or to declare them out of scope in writing. What is not available is discovering them after cutover.

External IDs, and the cost of not having them

Every object receiving migrated data carries a unique external ID holding the source system key, populated on the first load rather than added after the first incident.

That is one field, and it changes the character of the whole exercise.

It makes the migration re-runnable. With an external ID, the load is an upsert. Running it twice produces the same result as running it once. A batch that fails part way can be restarted. A defect found in a transformation can be fixed and the affected records reloaded in place. The rehearsal can be run repeatedly against the same target without accumulating duplicates. Without it, every load is an insert, every re-run is a second copy, and recovery from a bad batch is a deletion exercise on records a user may already have touched.

It makes reconciliation possible. Proving a source record arrived means finding it. Matching on a name and a date works until two people share both, which across twenty years of service records is not a hypothetical. Matching on the source key is exact.

It survives the project. After cutover, the external ID is how a question about a legacy record is answered, how the archive joins back to the live org, and how a later integration recognises what it is looking at. This is the third class of decision described in the data model decisions you cannot cheaply undo: the field is cheap to add at any time, but the mapping it would have recorded cannot be reconstructed afterwards, except by redoing the unreliable matching that caused the problem.

Where both source systems hold a version of the same entity, each gets its own external ID field. Collapsing the two keys into one loses the ability to say which system a record came from, and after a merge that is the first question asked whenever the two disagree.

History, audit trails, and what cannot be recreated

Created date and last modified date can be set on load where the org is configured to permit it. Field-level history cannot. The platform generates that from changes it observes, so a trail of changes made in a system being retired cannot be replayed into it, and neither can the identity of a user who left years ago.

This is not a technical obstacle to route around. It is a decision to make in the open, because where auditability obligations apply, quietly dropping the trail is the worst of the available options and the one that happens by default.

There are three honest choices.

Migrate the current state and keep the trail in the archive. The live org holds the record as it stands. The full change history stays in a read-only store, retained for as long as the obligation requires, joined back by external ID. We recommend this most often, because it keeps the org fast and the obligation met at the same time.

Reconstruct a summarised history as records. Where a change trail has real operational value, it is loaded as data on a purpose-built object rather than dressed up as platform history. It reads as data, it is reportable, and it is labelled as migrated rather than observed.

Establish that it is not required, and write that down. Sometimes the correct answer. It only counts when the person who owns the retention obligation has recorded the decision.

What to archive rather than migrate

Retention obligations pull against a clean org, and both pressures are legitimate. The obligation says keep it. Good design says do not put two decades of closed, untouched records in front of every user and every query that runs, for the reasons set out in why an org feels slow.

The reconciling principle is that retention is about being able to produce the record, not about the record living in the CRM.

So the boundary is drawn deliberately. Records that are operationally live, or that a user will realistically open beside a live record, are migrated. Records that exist to satisfy retention are archived to a store that is cheaper, immutable and access-controlled, indexed by the same external ID, with a documented path to retrieve one on request.

Two constraints shape where that store sits and who may read it, and both are questions about the class of obligation rather than about technology. Where the data may physically reside is one. Who may see which parts of it is the other, and access to historic clinical detail is usually narrower than access to the operational record, which means the archive inherits its own access design rather than borrowing the one built for the org. Segregation of duties applies to the migration team as much as to the users: the people who can move the data are not automatically the people entitled to read it. The same reasoning appears wherever an org sits inside a supervised organisation, which is the subject of what changes when the org belongs to a bank.

Data 360 earns its place here when the same person has to be recognised across the operational org and the retained history without copying the sensitive detail into the org to do it. Unifying an identity is not the same as loading a record, and keeping those two things separate is what lets the org stay minimal while the history stays complete.

Reconciliation that proves the migration

A migration is not finished when the load completes. It is finished when somebody who did not run it can verify it.

Counts alone do not do that. Equal row counts on both sides are entirely consistent with every value being wrong. So reconciliation is designed as a set of assertions written before the load, each one checkable by a person:

  • Every source record of each type has exactly one target record carrying its key, and no target record carries a key absent from the source.
  • For each migrated relationship, the number of children per parent matches the source, and no migrated child has an empty parent reference where the source had one.
  • For every transformed field, the distribution of resulting values matches the mapping decision. A status collapse designed to produce four values that produces five means a value was missed.
  • Amounts and dates are compared value by value across a sampled set, chosen to include the oldest records and the known-awkward ones rather than drawn at random.
  • A named set of real records, picked by the people who use them, is opened in the new system and read end to end by somebody who knows what it should say.

The output is a reconciliation report produced by the load process itself and kept as evidence that the migration was correct. Where auditability obligations apply, that artefact is not project overhead. It is part of what makes the new system defensible.

The cutover rehearsal

A migration you have not practised is a plan, not a procedure.

The rehearsal runs the whole sequence against a full-volume copy: extract, transform, load in order, reconcile, then the fallback. It is run more than once, and readiness is not that it worked. Readiness is that two consecutive runs produced the same result and the elapsed time is known rather than estimated.

The rehearsal is where the unpredicted things surface. A transformation that is fine on a sample and slow at full volume. A validation rule or an automation that fires during the load and rewrites values behind the migration, which is why automation is deliberately suspended for the load and its reinstatement is an explicit checklist item rather than an assumption. An integration user permission that is correct in the sandbox and absent in production.

The fallback is rehearsed too, and it has to be a real one. Saying you would restore from backup is not a fallback if nobody has timed the restore. The plan names the point of no return, the person who makes the call, the criteria they make it against, and what the organisation does for the people it serves during the window while the old system is brought back.

The decisions that were contested

Not migrating everything. The instinct where obligations apply is to bring it all, because keeping feels safer than deciding. The counter-argument is that an org holding two decades of untouched records is slower for everyone, harder to secure, and no better at meeting a retention obligation than an archive designed for exactly that. What settled it was writing down where each class of record would live and having the retention owner sign the list.

Rebuilding history as data rather than pretending. There was pressure to load a change trail into something that would look like platform history. We argued against it, because a trail that appears to have been generated by the system but was actually assembled by a migration script is a misleading artefact in precisely the situation where the trail matters most. It goes in as data, labelled as data.

Keeping the two source keys separate. The tidier design collapses both legacy identifiers into a single external ID. We kept both, because for years after a merge the most common data question is which system said what, and one field cannot answer it.

Manual review for ambiguous matches. Deduplicating people across two systems produces a band of near-matches that no rule resolves confidently. Automating that band would eventually merge two different people who share a surname, a suburb and a year of birth. On a service record that is not a data quality issue. The queue stays manual, and it stays manual on purpose.

What changes

The outcomes worth claiming here are operational, and they follow from the design rather than from effort.

BeforeAfterWhat made the difference
Two systems, two definitions of a caseOne definition, with the source distinction retainedProfiling before mapping, and a written decision per value
Every load a single-shot insertEvery load a re-runnable upsertA unique external ID per source system, populated first
Broken references found months laterParent-first order, empty references reported at loadLoad order designed, reconciliation asserting it held
Change history dropped by defaultHistory retained where required, archived where notThe retention owner signed the boundary before mapping
Everything migrated because keeping felt saferLive records migrated, retained records archivedRetention treated as producibility, not residency in the CRM
Cutover confidence resting on row countsCutover resting on a reconciliation reportAssertions written before the load, and run by the load

The second-order effect is the one leaders notice on the weekend itself. When the reconciliation report exists and the rehearsal has been run twice, the go or no-go conversation stops being a discussion about how everyone feels and becomes a reading of a document. That is a different meeting.

What we would tell you before starting

Spend the time at the front. Profiling and the archive boundary are the two activities that look like delay and are actually the whole schedule, because everything downstream is priced by how much has to be migrated and how many value decisions remain open when the build starts.

Get the external IDs in before the first load, on every object, one field per source system. It is the cheapest insurance in this kind of work, and there is no version of it you can add later at the same price.

And be honest early about history. Ask the person who owns the retention obligation what has to be producible and for how long, get the answer in writing, and design to it. Migrations that go badly in this setting rarely go badly at the load. They go badly at the moment somebody asks a question about a record from years ago, and the answer is that the system no longer knows.

Common questions

Answered, directly.

What buyers ask about delivering this in healthcare & life sciences.

Not as platform history. Salesforce generates field history from changes it observes, so a trail of changes made in a system being retired cannot be replayed into it, and neither can the identity of a user who no longer exists. The three honest options are to keep the trail in a retained archive joined back by external ID, to load a summarised trail as data on a purpose-built object and label it as migrated rather than observed, or to establish that it is not required and have the person who owns the retention obligation record that decision.

Especially then. A one-off migration is exactly the situation where a batch fails part way, a transformation defect is found after loading, or a rehearsal has to run again against the same target. An external ID turns each of those into a re-run rather than a deletion exercise. It also survives the project, because it is how a question about a legacy record is answered afterwards and how the archive joins back to the live org.

Start from what someone will realistically open beside a live record, and treat everything else as a retention question rather than a migration one. Records that are operationally live are migrated. Records that exist to satisfy an obligation go to a store that is cheaper, immutable and access-controlled, indexed by the same external ID, with a documented retrieval path. The boundary has to be agreed with whoever owns the retention obligation, in writing, before mapping starts.

Free architect conversation

Talk to an architect, not a sales rep.

60 seconds to brief us, and a certified architect replies within one business day.

What are you looking to architect?

Pick the closest fit. You can add detail in a moment.

Which clouds or systems are in scope?

Optional. Choose any that apply, or skip ahead.

Where does your org stand today?

Optional. A few sentences is plenty: what is working, what is stuck, and what you want to be true. Or skip ahead and tell us on the call.

Who should the architect reach?

A certified architect will reply to these details.

Takes about 30–60 seconds · No obligation · Architect replies within one business day

Protected by reCAPTCHA. Google's Privacy Policy and Terms apply.

The thinking behind this

Related reading

Where this sits

Salesforce Integration Services

This work is delivered through our salesforce integration services practice.

Talk to us about your integrations

More delivery

Related case studies

  • SynconAI Consulting are Simply the Best in the Business When it comes to Salesforce implementation and AI-powered solutions, SynconAI are in a league of their own. Their expertise, dedication, and ability to deliver results that truly move the needle sets them apart from every other consulting partner we've worked with. What they achieved with our Sales Cloud, Service Cloud, and custom Agentforce agent has completely transformed how we operate streamlining our pipelines and our customer service, and automating tasks that used to consume hours of our team's time. They don't just implement technology they transform businesses. If you want the best, you work with their team.

    Jack BennettConsumer Goods & RetailUnited States

  • I had a very urgent deadline for our project reporting to be delivered and needed to build the module, dashboard and output reports in Salesforce. SynconAI were very responsive - they met with me online, responded to my emails quickly and took calls - whatever was needed to progress the work quickly. We are thrilled with the outcome and will continue to work with SynconAI in the future to continue to build our Salesforce capability and platform.

    Salesforce Managed ServicesAustralia

  • The team at SynconAI were fantastic, and promptly delivered on each project. They were able to guide us through every stage and made sure we were satisfied with the outcomes on multiple scopes of work.

    ManufacturingAustralia

  • They have been great and helping us transform out business by bringing what I conceptualize to life. Great at translating process/workflow needs into a solution. Been a pleasure work with and they're a critical part of our team and will be instrumental into bringing about my vision.

    Financial ServicesUnited States

  • Working with SynconAI was a seamless and highly professional experience from start to finish. They took the time to deeply understand our business processes before designing and implementing a Salesforce solution tailored specifically to our operational needs. The team demonstrated strong technical expertise across Salesforce configuration, automation, integrations, reporting, and user experience design.

    Salesforce Implementation