Introducción: Por Qué la Migración de HL7 v2 a FHIR es Inevitable
HL7 v2.x ha servido fielmente a la interoperabilidad sanitaria desde finales de los años 80, y la mayoría de las interfaces hospitalarias mundiales siguen intercambiando admisiones ADT, resultados de laboratorio ORU y órdenes ORM a través de conexiones MLLP con tubería. Sin embargo, el panorama está cambiando de forma irreversible. Las normas de interoperabilidad de la ONC y CMS de EE. UU. exigen APIs FHIR R4 para el acceso a datos de pacientes. SMART on FHIR habilita una nueva generación de aplicaciones clínicas. Las plataformas EHR en la nube —Epic, Oracle Health Millennium, athenahealth— están invirtiendo en APIs nativas FHIR. Los proyectos de migración ya no son opcionales para los sistemas sanitarios que quieren mantenerse competitivos y en cumplimiento normativo.
Esta guía explica el desafío técnico central de mapear mensajes HL7 v2.x a recursos FHIR R4, recorre los tipos de mensajes más comunes (ADT, ORU, ORM) y ofrece orientación práctica para arquitectos de integración y analistas de interfaces HL7 que planifican o ejecutan una migración. Todos los ejemplos de código siguen la especificación FHIR R4 y la guía de implementación HL7 v2 a FHIR publicada por HL7 International. Este artículo es educativo — valide siempre el resultado con sus perfiles de guía de implementación antes de desplegarlo en producción.
La Diferencia Arquitectónica Fundamental
El reto central de la migración de HL7 v2 a FHIR es arquitectónico. HL7 v2 es un formato plano orientado a documentos. Un único mensaje ADT^A01 contiene toda la información clínica y demográfica en una secuencia lineal de segmentos delimitados por barras. Las relaciones entre los elementos de datos son implícitas: se asume que el segmento PID describe al paciente del segmento PV1 que le sigue. No hay normalización, no hay clave foránea, no hay grafo.
FHIR, por el contrario, es un estándar orientado a grafos y nativo de REST. Los conceptos clínicos se modelan como recursos discretos —Patient, Encounter, Observation, Practitioner, Location— y las relaciones se expresan como referencias tipadas entre recursos. Un recurso Patient está vinculado a un recurso Encounter, que referencia una Location y un Practitioner. El bundle no es una secuencia lineal; es un subgrafo conectado del modelo de información clínica.
Esto significa que convertir un mensaje HL7 v2 a FHIR no es un simple renombrado de campos. Requiere: descomponer tipos de datos compuestos (XPN, XAD, XCN, CX) en sus componentes; crear nuevos recursos para las entidades referenciadas (profesionales de PV1-7, ubicaciones de PV1-3); generar IDs únicos para cada recurso; resolver la terminología (valores de tablas v2 a sistemas de códigos FHIR); y ensamblar todos los recursos en un Bundle FHIR tipado con URLs de entrada correctas.
Mapeo de Mensajes ADT a Patient y Encounter
Los mensajes ADT (Admisión/Alta/Traslado) son el tipo de mensaje HL7 de mayor volumen en la mayoría de los hospitales. Un ADT^A01 admite a un paciente, el ADT^A03 lo da de alta, el ADT^A08 actualiza la demografía y el ADT^A04 registra una visita ambulatoria. Todos los eventos ADT mapean a un par central de recursos FHIR: Patient y Encounter.
PID → Recurso Patient
El segmento de Identificación del Paciente (PID) es la fuente autoritativa de datos demográficos del paciente. Mapeos clave:
- PID-3 (Lista de ID del Paciente, CX): Mapea a
Patient.identifier[]. El tipo de datos CX contiene un número de ID (componente 1), un código de tipo de ID (componente 5, p. ej., "MR" para número de Historia Clínica, "SS" para número de Seguridad Social) y una autoridad asignadora (componente 4). Cada repetición de PID-3 debe generar una entrada de identificador en el array Patient.identifier. El código de tipo de la tabla 0203 se mapea aidentifier.type.coding.codeusando el sistemahttp://terminology.hl7.org/CodeSystem/v2-0203. - PID-5 (Nombre del Paciente, XPN): Mapea a
Patient.name[]. El componente 1 de XPN es el apellido, el componente 2 el nombre, el componente 3 el segundo nombre/inicial, el componente 5 el prefijo y el componente 4 el sufijo. El valor de HumanName.use en FHIR debe serofficialpara el nombre principal. - PID-7 (Fecha/Hora de Nacimiento, TS): Mapea a
Patient.birthDate. Elimine los componentes de hora si están presentes —birthDate es una fecha FHIR (AAAA-MM-DD), no un dateTime. - PID-8 (Sexo Administrativo, IS): Mapea a
Patient.genderusando el sistema de códigoshttp://hl7.org/fhir/administrative-gender. Los valores M/F/O/U de la tabla 0001 de HL7 v2 mapean a male/female/other/unknown. - PID-11 (Dirección del Paciente, XAD): Mapea a
Patient.address[]. El componente 1 de XAD es la calle, el 3 la ciudad, el 4 el estado/provincia, el 5 el código postal, el 6 el país y el 7 el tipo de dirección. - PID-13/14 (Números de Teléfono, XTN): Mapean a
Patient.telecom[]con sistema "phone" y uso "home"/"work" respectivamente.
PV1 → Recurso Encounter
El segmento de Visita del Paciente (PV1) mapea al recurso FHIR Encounter:
- PV1-2 (Clase de Paciente, IS): Mapea a
Encounter.classusando la tabla 0004. I (Ingresado) → código ACT IMP, O (Ambulatorio) → AMB, E (Urgencias) → EMER. Use el sistemahttp://terminology.hl7.org/CodeSystem/v3-ActCode. - PV1-3 (Ubicación del Paciente Asignado, PL): Mapea a
Encounter.location[0].location. El componente 1 de PL es el Punto de Atención (sala), el componente 2 la habitación y el componente 3 la cama. - PV1-7 (Médico Responsable, XCN): Mapea a
Encounter.participant[]con código de tipo ATND (responsable). El componente 1 de XCN es el ID del proveedor, los componentes 2-3 son el apellido y el nombre. - PV1-19 (Número de Visita, CX): Mapea a
Encounter.identifier[]—el identificador de negocio principal para la visita o cuenta hospitalaria. - PV1-44 (Fecha/Hora de Ingreso, TS): Mapea a
Encounter.period.start. - PV1-45 (Fecha/Hora de Alta, TS): Mapea a
Encounter.period.end. Establezca este valor solo para eventos de alta (ADT^A03) o cuando la fecha esté presente. - Encounter.status: Se deriva del código de evento ADT. A01/A04 → "in-progress", A03 → "finished", A08 → "in-progress".
La referencia Encounter.subject debe apuntar al recurso Patient generado usando su fullUrl del bundle FHIR (p. ej., urn:uuid:pac-abc123).
Mapeo de Mensajes ORU a DiagnosticReport y Observations
Los mensajes ORU^R01 (Resultado de Observación) transportan resultados de laboratorio, microbiología, radiología y clínicos. La representación FHIR agrupa los resultados usando un recurso DiagnosticReport que referencia uno o más recursos Observation —permitiendo búsquedas y agregaciones por informe mientras se mantiene la granularidad de los resultados individuales.
OBR → DiagnosticReport
- OBR-4 (Identificador Universal del Servicio, CWE): Mapea a
DiagnosticReport.code. El componente 1 de CWE es el código, el 2 el texto de visualización y el 3 el sistema de codificación (p. ej., "LN" para LOINC, "L" para local). Convierta "LN" al URI del sistema LOINChttp://loinc.org. - OBR-7 (Fecha/Hora de la Observación, TS): Mapea a
DiagnosticReport.effectiveDateTime. - OBR-25 (Estado del Resultado, ID): Mapea a
DiagnosticReport.status. F → final, P → partial, C → corrected, X → cancelled. - DiagnosticReport.result: Array de referencias, una por segmento OBX, cada una apuntando al fullUrl del bundle del recurso Observation correspondiente.
OBX → Recursos Observation
Cada segmento OBX en un ORU^R01 se convierte en un recurso FHIR Observation separado. La clave es el campo OBX-2 (Tipo de Valor), que determina cómo representar el resultado:
- NM (Numérico): Use
Observation.valueQuantitycon el valor (OBX-5 como decimal), la unidad (OBX-6 como cadena) y opcionalmente el sistema UCUM (http://unitsofmeasure.org) si la unidad es un código UCUM válido. - ST/TX/FT (Cadena/Texto/Formateado): Use
Observation.valueString. - CWE/CE (Codificado): Use
Observation.valueCodeableConceptcon codificación de los componentes de OBX-5. - DT/TS (Fecha/Fecha y Hora): Use
Observation.valueDateTime.
OBX-3 mapea a Observation.code, OBX-6 (unidades) a Observation.valueQuantity.unit, OBX-7 (rango de referencia) a Observation.referenceRange[].text, OBX-8 (indicador de anormalidad) a Observation.interpretation usando la tabla 0078 de HL7 v2, y OBX-11 (estado del resultado) a Observation.status.
Mapeo de Mensajes ORM a ServiceRequest
ORM^O01 (Mensaje de Orden) se usa para órdenes de laboratorio, radiología y terapia. En FHIR R4, una orden general mapea a un recurso ServiceRequest, aunque las órdenes de imagen diagnóstica también pueden representarse como ImagingStudy.
- ORC-2 (Número de Orden del Solicitante, EI): Mapea a
ServiceRequest.identifiercon tipo "PLAC" (solicitante). - ORC-3 (Número de Orden del Ejecutor, EI): Mapea a una segunda entrada de identificador con tipo "FILL" (ejecutor) si está presente.
- ORC-5 (Estado de la Orden, ID): Mapea a
ServiceRequest.status. IP → active, CM → completed, CA → revoked, NW → draft. - ORC-12 (Proveedor que Solicita, XCN): Mapea a
ServiceRequest.requester. - OBR-4 (ID Universal del Servicio, CWE): Mapea a
ServiceRequest.code. - OBR-5 (Prioridad, ID): Mapea a
ServiceRequest.priority. S (Urgente) → stat, R (Rutina) → routine, A (Lo antes posible) → asap. - OBR-6 (Fecha/Hora Solicitada, TS): Mapea a
ServiceRequest.occurrenceDateTime.
Ensamblaje del Bundle FHIR
Todos los recursos generados deben combinarse en un único Bundle FHIR. Un bundle de tipo collection es el más sencillo —tiene type: "collection" y contiene entradas con fullUrl y resource. Un bundle de tipo transaction añade un objeto request a cada entrada (method: PUT, url: Patient/{id}), permitiendo enviar el bundle completo al endpoint /$transaction de un servidor FHIR para persistencia atómica.
Los IDs de recurso deben ser UUIDs (urn:uuid:...) al generar el bundle fuera de línea. Las referencias entre recursos usan estos fullUrls —por ejemplo, Encounter.subject = { reference: "urn:uuid:patient-id" }. El Bundle.id y Bundle.timestamp deben establecerse con una cadena datetime ISO-8601 actual usando new Date().toISOString().
Errores Comunes en la Migración y Cómo Evitarlos
Incluso las migraciones bien planificadas se encuentran con problemas predecibles. Estos son los errores más frecuentes:
- Sistemas de identificadores ambiguos: Los valores CX de PID-3 suelen tener nombres de autoridades asignadoras locales (p. ej., "HOSPITAL") sin OID formal. Establezca un registro de sistemas de nombres — mapee cada autoridad asignadora a un recurso NamingSystem con una URL canónica.
- Códigos de tablas v2 no listados: OBX-8 (indicadores de anormalidad), PID-8 (sexo) y PV1-2 (clase de paciente) usan valores de tablas HL7 v2 que deben mapearse a valores del sistema de códigos FHIR. Mantenga una tabla de traducción en su middleware.
- Nombres parciales en XCN: PV1-7 (médico responsable) es un XCN que puede contener solo un ID de proveedor sin componentes de nombre. Maneje siempre el formato ID-primero (componente 1 = ID, componentes 2-3 = nombre).
- Números de visita ausentes en PV1-19: Algunas interfaces EHR omiten el número de visita de PV1-19. Use ORC-2 o un identificador basado en UUID como reserva para garantizar que cada Encounter tenga un identificador consultable.
- Unidades en UCUM: Las unidades de texto libre de OBX-6 (p. ej., "mg/dL", "10*3/uL") deben convertirse a códigos UCUM siempre que sea posible. Use una biblioteca de búsqueda UCUM para automatizar esta conversión.
- Pérdida de datos en segmentos Z: Los segmentos Z locales (ZDG para diagnósticos, ZPI para seguros) contienen datos clínicos sin mapeo FHIR estándar. Use extensiones FHIR (modifierExtension o definiciones de extensión estándar) para preservar estos datos y documéntelas en su guía de implementación.
Pruebas y Validación
Todo proyecto de migración de HL7 v2 a FHIR necesita una estrategia de pruebas sólida. Como mínimo, valide su lógica de mapeo con:
- Pruebas unitarias a nivel de campo: Pruebe cada mapeo de campos PID, PV1, OBR, OBX y ORC de forma aislada con valores límite —campos vacíos, campos con múltiples repeticiones, caracteres especiales en nombres y formatos de fecha no estándar.
- Validador de recursos FHIR: Ejecute todos los recursos generados a través del validador oficial FHIR de HL7 (
validator.fhir.org). Valide tanto contra la especificación base FHIR R4 como contra los perfiles de su guía de implementación objetivo (p. ej., US Core v6). - Pruebas de ida y vuelta: Si su arquitectura requiere traducción bidireccional, confirme que las conversiones FHIR→v2 producen mensajes que pueden ser reingresados por sus interfaces HL7 v2 sin pérdida de información.
- Pruebas de volumen con datos representativos de producción: Analice al menos 10.000 mensajes de producción con su mapeador antes del lanzamiento. Mida tasas de fallo, frecuencia de advertencias y cobertura de campos para identificar brechas sistémicas.
Use la herramienta gratuita HL7 v2 a FHIR en este sitio para probar mensajes individuales e inspeccionar la tabla de mapeo a nivel de campo antes de construir su pipeline de producción.
Conclusión
La migración de HL7 v2 a FHIR es una tarea de ingeniería técnicamente exigente pero bien comprendida. Los principios clave son: comprender la diferencia arquitectónica (segmentos planos → grafo de recursos), mapear meticulosamente cada tipo de datos CX/XPN/XCN, generar sistemas de identificadores FHIR adecuados a partir de las autoridades asignadoras de HL7, traducir la terminología usando mappings de sistemas de códigos establecidos y validar la salida contra los perfiles de la guía de implementación. Con un diseño cuidadoso, pruebas exhaustivas y una tabla de trazabilidad a nivel de campo, su equipo de integración puede migrar interfaces v2 a FHIR R4 sin perder semántica clínica ni romper sistemas de destino.
Este artículo es exclusivamente educativo. Los ejemplos mostrados son sintéticos. Valide siempre la salida FHIR contra los perfiles de la guía de implementación de su organización y consulte a profesionales cualificados en informática sanitaria para los despliegues en producción.