>Welcome to MedictGet StartedMigrating to Medict

Migrating to Medict

A comprehensive guide to migrating your existing healthcare application to Medict.

Migration Overview

Migrating to Medict involves moving your healthcare data and workflows to a FHIR-compliant platform. This guide covers common migration scenarios and best practices.

Pre-Migration Planning

1. Data Assessment

Before migrating, assess your current data:

  • Data Volume: Count records by type (patients, encounters, observations)
  • Data Quality: Identify missing or invalid data
  • Data Relationships: Map how different data types relate to each other
  • Custom Fields: Document any non-standard fields

2. FHIR Mapping

Map your existing data model to FHIR resources:

// Example mapping from legacy system to FHIR
const legacyToFhirMapping = {
  'patient_id': 'Patient.id',
  'first_name': 'Patient.name[0].given[0]',
  'last_name': 'Patient.name[0].family',
  'date_of_birth': 'Patient.birthDate',
  'email': 'Patient.telecom[0].value',
  'phone': 'Patient.telecom[1].value'
};

3. Migration Strategy

Choose your migration approach:

  • Big Bang: Migrate everything at once
  • Phased: Migrate in stages by module or data type
  • Parallel: Run both systems simultaneously
  • Gradual: Migrate users incrementally

Data Migration

Patient Data Migration

import { MedictClient } from '@medplum/core';

async function migratePatients(legacyPatients) {
  const client = new MedictClient({
    baseUrl: 'https://api.medplum.com',
    clientId: 'your-client-id'
  });

  const results = [];
  
  for (const legacyPatient of legacyPatients) {
    try {
      const fhirPatient = {
        resourceType: 'Patient',
        identifier: [{
          use: 'usual',
          value: legacyPatient.patient_id
        }],
        name: [{
          use: 'official',
          family: legacyPatient.last_name,
          given: [legacyPatient.first_name]
        }],
        birthDate: legacyPatient.date_of_birth,
        gender: legacyPatient.gender,
        telecom: [
          {
            system: 'email',
            value: legacyPatient.email,
            use: 'home'
          },
          {
            system: 'phone',
            value: legacyPatient.phone,
            use: 'home'
          }
        ]
      };

      const createdPatient = await client.createResource(fhirPatient);
      results.push({
        legacyId: legacyPatient.patient_id,
        fhirId: createdPatient.id,
        status: 'success'
      });
    } catch (error) {
      results.push({
        legacyId: legacyPatient.patient_id,
        status: 'error',
        error: error.message
      });
    }
  }

  return results;
}

Clinical Data Migration

async function migrateObservations(legacyObservations, patientMapping) {
  const results = [];
  
  for (const obs of legacyObservations) {
    const fhirObservation = {
      resourceType: 'Observation',
      status: 'final',
      category: [{
        coding: [{
          system: 'http://terminology.hl7.org/CodeSystem/observation-category',
          code: obs.category_code
        }]
      }],
      code: {
        coding: [{
          system: obs.code_system,
          code: obs.code,
          display: obs.display_name
        }]
      },
      subject: {
        reference: `Patient/${patientMapping[obs.patient_id]}`
      },
      effectiveDateTime: obs.observation_date,
      valueQuantity: {
        value: obs.value,
        unit: obs.unit
      }
    };

    try {
      const created = await client.createResource(fhirObservation);
      results.push({ legacyId: obs.id, fhirId: created.id, status: 'success' });
    } catch (error) {
      results.push({ legacyId: obs.id, status: 'error', error: error.message });
    }
  }

  return results;
}

Application Migration

API Integration

Replace your existing API calls with Medict SDK:

// Before: Custom API
const response = await fetch('/api/patients', {
  method: 'GET',
  headers: { 'Authorization': `Bearer ${token}` }
});
const patients = await response.json();

// After: Medict SDK
const patients = await medplum.searchResources('Patient', {
  name: 'Smith'
});

Authentication Migration

// Before: Custom auth
const token = localStorage.getItem('authToken');
const isAuthenticated = !!token;

// After: Medict auth
import { useMedict } from '@medplum/react';

function App() {
  const medplum = useMedict();
  const isAuthenticated = medplum.getActiveLogin() !== undefined;
  
  return (
    <div>
      {isAuthenticated ? <Dashboard /> : <Login />}
    </div>
  );
}

UI Component Migration

// Before: Custom patient card
function PatientCard({ patient }) {
  return (
    <div className="patient-card">
      <h3>{patient.firstName} {patient.lastName}</h3>
      <p>DOB: {patient.dateOfBirth}</p>
    </div>
  );
}

// After: Medict patient card
import { PatientCard } from '@medplum/react';

function PatientCard({ patientId }) {
  return <PatientCard patientId={patientId} />;
}

Testing Your Migration

Data Validation

async function validateMigration(patientMapping) {
  const validationResults = [];
  
  for (const [legacyId, fhirId] of Object.entries(patientMapping)) {
    try {
      const fhirPatient = await client.readResource('Patient', fhirId);
      const legacyPatient = await getLegacyPatient(legacyId);
      
      const validation = {
        legacyId,
        fhirId,
        nameMatch: fhirPatient.name?.[0]?.family === legacyPatient.last_name,
        dobMatch: fhirPatient.birthDate === legacyPatient.date_of_birth,
        genderMatch: fhirPatient.gender === legacyPatient.gender
      };
      
      validationResults.push(validation);
    } catch (error) {
      validationResults.push({
        legacyId,
        fhirId,
        error: error.message
      });
    }
  }
  
  return validationResults;
}

Performance Testing

async function performanceTest() {
  const startTime = Date.now();
  
  // Test search performance
  const searchResults = await client.searchResources('Patient', {
    name: 'Smith'
  });
  
  const searchTime = Date.now() - startTime;
  
  // Test create performance
  const createStart = Date.now();
  await client.createResource({
    resourceType: 'Patient',
    name: [{ family: 'Test', given: ['Performance'] }]
  });
  const createTime = Date.now() - createStart;
  
  return {
    searchTime,
    createTime,
    searchCount: searchResults.length
  };
}

Common Migration Challenges

1. Data Format Differences

Problem: Legacy system uses different date formats Solution: Convert dates to ISO 8601 format

function convertDate(legacyDate) {
  // Convert MM/DD/YYYY to YYYY-MM-DD
  const [month, day, year] = legacyDate.split('/');
  return `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
}

2. Missing Required Fields

Problem: Legacy data missing FHIR required fields Solution: Provide default values

function ensureRequiredFields(patient) {
  return {
    ...patient,
    resourceType: 'Patient',
    name: patient.name || [{ use: 'official', family: 'Unknown' }],
    gender: patient.gender || 'unknown'
  };
}

3. Large Dataset Migration

Problem: Migrating millions of records Solution: Use batch processing and pagination

async function migrateLargeDataset(records, batchSize = 100) {
  const results = [];
  
  for (let i = 0; i < records.length; i += batchSize) {
    const batch = records.slice(i, i + batchSize);
    const batchResults = await Promise.allSettled(
      batch.map(record => migrateRecord(record))
    );
    
    results.push(...batchResults);
    
    // Add delay to avoid rate limiting
    await new Promise(resolve => setTimeout(resolve, 1000));
  }
  
  return results;
}

Post-Migration Checklist

  • [ ] Verify all data migrated successfully
  • [ ] Test all application functionality
  • [ ] Update user documentation
  • [ ] Train staff on new system
  • [ ] Set up monitoring and alerts
  • [ ] Plan legacy system decommissioning
  • [ ] Update integrations and APIs
  • [ ] Test backup and recovery procedures

Migration Support

Need help with your migration? Our team can assist with:

  • Migration planning and strategy
  • Data mapping and transformation
  • Custom migration scripts
  • Performance optimization
  • Testing and validation

Contact our migration team for personalized assistance.

Next Steps