Legacy Migration Plan

Legacy Data Migration & Validation Blueprint

1. Migration Scope & Schema Strategy

The legacy system stores patient records, visit histories, and financial ledgers across an un-indexed SQL database filled with cleartext identifiers and un-coded, free-text diagnoses.

Rendering Chart

1.1 Legacy-to-Target Domain Target Matrix

Legacy Entity TypeTarget Module SchemaTransformation ConstraintCoding Standard Applied
tbl_demographicsmaster_patient_indexConvert names to byte arrays using AES-256-GCM field encryption. Generate deterministically hashed phone records for lookups.National Unique Patient ID (NUPI)
tbl_visit_historypatient_encountersParse text strings into discrete encounter class attributes (OUTPATIENT, INPATIENT).Dual-token identity matching
tbl_diagnosesclinical_consultationsRun string-matching scripts to map legacy text inputs to standardized codes. Unmapped entries default to a REVIEWS_PENDING flag.WHO ICD-11 Taxonomy
tbl_billing_ledgerfinancial_ledger_entriesRe-aggregate raw balance parameters into an append-only, transaction split architecture.Double-Entry Bookkeeping

2. Production Extraction, Transformation & Loading (ETL) Script

The production ETL migration utility runs within an isolated staging container. It streams legacy records sequentially to protect system memory limits.

# scripts/migrate_legacy_records.py
import os
import mysql.connector
import psycopg2
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from datetime import datetime

def execute_legacy_migration_pipeline():
    """
    Production ETL script that extracts legacy data, encrypts patient 
    identifiers, maps fields, and stream-writes to PostgreSQL 16.
    """
    # 1. Initialize local cryptographic keys
    master_key = bytes.fromhex(os.getenv("FIELD_ENCRYPTION_MASTER_KEY"))
    aesgcm = AESGCM(master_key)
    
    # 2. Establish connections to source and target databases
    legacy_conn = mysql.connector.connect(host="192.168.10.30", user="migration", password="*", database="legacy_hmis")
    target_conn = psycopg2.connect("postgres://hmis_master:*@127.0.0.1:5432/hmis_prod")
    
    legacy_cursor = legacy_conn.cursor(dictionary=True)
    target_cursor = target_conn.cursor()
    
    # Stream-fetch legacy records to minimize memory consumption
    legacy_cursor.execute("SELECT patient_id, first_name, last_name, national_id, dob, gender FROM tbl_demographics;")
    
    print("Beginning record migration and field encryption pipeline...")
    
    for row in legacy_cursor:
        nonce = os.urandom(12)
        
        # Encrypt cleartext fields before writing to the database
        encrypted_first_name = nonce + aesgcm.encrypt(nonce, row['first_name'].encode('utf-8'), None)
        encrypted_last_name = nonce + aesgcm.encrypt(nonce, row['last_name'].encode('utf-8'), None)
        
        try:
            target_cursor.execute(
                """
                INSERT INTO master_patient_index (
                    national_id_passport, first_name_encrypted, last_name_encrypted, date_of_birth, gender, primary_phone_hash, created_at
                ) VALUES (%s, %s, %s, %s, %s, %s, %s);
                """,
                (
                    row['national_id'],
                    psycopg2.Binary(encrypted_first_name),
                    psycopg2.Binary(encrypted_last_name),
                    row['dob'],
                    row['gender'].upper(),
                    "MIGRATED_PRESERVED_RECORD_HASH",
                    datetime.now()
                )
            )
        except psycopg2.errors.UniqueViolation:
            target_conn.rollback()
            continue # Bypass duplicate entries to preserve data integrity
            
    target_conn.commit()
    print("Migration pipeline completed successfully.")

if __name__ == "__main__":
    execute_legacy_migration_pipeline()

3. Data Cleansing & Validation Controls

To ensure data accuracy post-migration, the system runs automated validation tests across the target database before going live.

3.1 Data Validation Procedures

Rendering Chart
  • Row Count Verification: Matches total records extracted from the legacy system against total entries populated in PostgreSQL to verify that no rows were dropped during migration.
  • Cryptographic Decryption Test: Extracts a random sample of encrypted binary records from master_patient_index and verifies they can be decrypted back to their original cleartext format, ensuring encryption keys are configured correctly.
  • ICD-11 Diagnostics Validation Check: Runs an automated audit query to catch any diagnostic records that failed the string-matching transformation step, tracking unmapped entries for the medical records team:

Document Verification Block

Author: Ian Wataka
Target Scope: Legacy System ETL, Data Validation, and Cryptographic Cleansing