제공자 도구 및 대시보드

弘익人間 (Hongik Ingan) - "널리 인간을 이롭게 하라"
Seamless integration with existing healthcare systems ensures digital therapy becomes part of comprehensive care rather than an isolated silo. True benefit comes from coordination across the entire care ecosystem.

7.1 HL7 FHIR Standards

Fast Healthcare Interoperability Resources (FHIR) is the latest standard for exchanging healthcare information electronically. Developed by HL7, FHIR uses modern web technologies (RESTful APIs, JSON/XML, OAuth2) making integration far simpler than previous standards.

FHIR Resource Types for Mental Health

FHIR Resource Purpose Example Use Mapped WIA Data
Patient Demographics and identifiers Linking digital therapy user to EHR patient Name, DOB, MRN, contact info
Condition Diagnoses and problem list Major Depressive Disorder, GAD Primary diagnosis, comorbidities
Observation Clinical measurements PHQ-9 score, mood ratings Assessment scores, vital signs
CarePlan Treatment plans and goals 12-week CBT program, therapy goals Treatment plan, milestones
Procedure Interventions performed Therapy session, assessment administration Session records, interventions
MedicationStatement Current medications Antidepressant regimen Medication tracking (if applicable)
DocumentReference Clinical documents Progress notes, discharge summaries Session notes, reports

FHIR Implementation

// FHIR Client Implementation
class FHIRIntegrationService {
  private client: FHIRClient;
  private baseUrl: string;
  
  constructor(config: FHIRConfig) {
    this.client = new FHIRClient({
      baseUrl: config.ehrBaseUrl,
      auth: {
        type: 'oauth2',
        clientId: config.clientId,
        clientSecret: config.clientSecret,
        tokenUrl: config.tokenUrl
      }
    });
    this.baseUrl = config.ehrBaseUrl;
  }
  
  // Read patient data from EHR
  async getPatientData(patientId: string): Promise {
    const response = await this.client.request({
      url: `${this.baseUrl}/Patient/${patientId}`,
      method: 'GET',
      headers: {
        'Accept': 'application/fhir+json'
      }
    });
    
    return this.parseFHIRResource(response.data);
  }
  
  // Write PHQ-9 score to EHR as Observation
  async recordPHQ9Score(
    patientId: string,
    score: number,
    date: Date
  ): Promise {
    const observation: FHIRObservation = {
      resourceType: 'Observation',
      status: 'final',
      category: [{
        coding: [{
          system: 'http://terminology.hl7.org/CodeSystem/observation-category',
          code: 'survey',
          display: 'Survey'
        }]
      }],
      code: {
        coding: [{
          system: 'http://loinc.org',
          code: '44249-1',
          display: 'PHQ-9 total score'
        }]
      },
      subject: {
        reference: `Patient/${patientId}`
      },
      effectiveDateTime: date.toISOString(),
      valueInteger: score,
      interpretation: [{
        coding: [{
          system: 'http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation',
          code: this.getInterpretationCode(score)
        }]
      }],
      component: this.getPHQ9Components(score)
    };
    
    await this.client.create(observation);
  }
  
  // Create therapy session as Procedure
  async recordTherapySession(
    patientId: string,
    session: TherapySession
  ): Promise {
    const procedure: FHIRProcedure = {
      resourceType: 'Procedure',
      status: 'completed',
      category: {
        coding: [{
          system: 'http://snomed.info/sct',
          code: '276205009',
          display: 'Psychotherapy'
        }]
      },
      code: {
        coding: [{
          system: 'http://snomed.info/sct',
          code: this.getTherapyCode(session.type),
          display: this.getTherapyDisplay(session.type)
        }]
      },
      subject: {
        reference: `Patient/${patientId}`
      },
      performedPeriod: {
        start: session.startTime.toISOString(),
        end: session.endTime.toISOString()
      },
      note: [{
        text: this.generateSessionNote(session)
      }]
    };
    
    await this.client.create(procedure);
  }
  
  private getTherapyCode(type: string): string {
    const codes = {
      'CBT': '38678006',      // Cognitive behavioral therapy
      'DBT': '719984009',     // Dialectical behavior therapy
      'ACT': '710925007',     // Acceptance and commitment therapy
      'IPT': '76168009',      // Interpersonal psychotherapy
      'MBCT': '718077003'     // Mindfulness-based cognitive therapy
    };
    return codes[type] || '75516001'; // Generic psychotherapy
  }
}

7.2 Major EHR System Integration

The US healthcare market is dominated by a few major EHR vendors. Successful integration requires vendor-specific implementations alongside standard FHIR APIs.

EHR Vendor Integration

EHR System Market Share Integration Method Key Challenges
Epic 31% (largest) FHIR API + App Orchard marketplace Strict certification requirements, slow approval
Cerner (Oracle Health) 25% FHIR API + Cerner Code Console Multiple data models across versions
Meditech 16% FHIR API (newer versions), HL7 v2 (legacy) Wide variation in implementation maturity
Allscripts 7% FHIR API + Developer Portal Multiple EHR products with different APIs
athenahealth 5% athenaNet API (proprietary + FHIR) Cloud-only, specific auth requirements

Epic Integration Example

// Epic-specific integration via App Orchard
class EpicIntegration extends FHIRIntegrationService {
  private epicClient: EpicClient;
  
  async initialize(config: EpicConfig): Promise {
    // Epic uses SMART on FHIR for authorization
    const smartClient = await this.initializeSMART({
      clientId: config.clientId,
      redirectUri: config.redirectUri,
      scope: [
        'launch',
        'patient/Patient.read',
        'patient/Observation.read',
        'patient/Observation.write',
        'patient/Condition.read',
        'patient/Procedure.write',
        'patient/CarePlan.read',
        'patient/CarePlan.write'
      ].join(' ')
    });
    
    this.epicClient = new EpicClient(smartClient);
  }
  
  // Epic-specific: Create Questionnaire Response for PHQ-9
  async recordPHQ9Epic(
    patientId: string,
    responses: PHQ9Responses
  ): Promise {
    // Epic prefers QuestionnaireResponse over generic Observation
    const questionnaireResponse: FHIRQuestionnaireResponse = {
      resourceType: 'QuestionnaireResponse',
      status: 'completed',
      questionnaire: 'http://epic.com/fhir/Questionnaire/PHQ9',
      subject: {
        reference: `Patient/${patientId}`
      },
      authored: new Date().toISOString(),
      item: responses.answers.map((answer, index) => ({
        linkId: `PHQ9-${index + 1}`,
        text: this.getQuestionText(index + 1),
        answer: [{
          valueInteger: answer
        }]
      }))
    };
    
    await this.epicClient.create(questionnaireResponse);
    
    // Also create summary Observation
    await this.recordPHQ9Score(
      patientId,
      responses.totalScore,
      new Date()
    );
  }
  
  // Epic In Basket messaging for therapist communication
  async sendInBasketMessage(
    providerId: string,
    subject: string,
    body: string,
    priority: 'routine' | 'urgent'
  ): Promise {
    // Epic proprietary API for provider messaging
    await this.epicClient.sendMessage({
      recipient: {
        type: 'Provider',
        id: providerId
      },
      subject,
      body,
      priority,
      category: 'Clinical'
    });
  }
}

7.3 Data Synchronization Strategy

Bidirectional sync between digital therapy platform and EHR systems requires careful orchestration to avoid data conflicts, duplication, and compliance issues.

Sync Architecture

Data Synchronization Flow: ══════════════════════════════════ ┌─────────────────────┐ ┌──────────────────┐ │ Digital Therapy │◄───────►│ EHR System │ │ Platform │ FHIR │ (Epic, etc.) │ └──────────┬──────────┘ API └────────┬─────────┘ │ │ │ │ ▼ ▼ ┌────────────┐ ┌────────────┐ │ Local │ │ EHR │ │ Database │ │ Database │ └────────────┘ └────────────┘ │ ▼ ┌────────────────────────────────────────┐ │ Sync Orchestration Engine │ ├────────────────────────────────────────┤ │ • Conflict Resolution │ │ • Deduplication │ │ • Transformation & Mapping │ │ • Retry Logic │ │ • Audit Logging │ └────────────────────────────────────────┘ Sync Operations: 1. Patient demographics: EHR → Platform (read-only) 2. Assessment scores: Platform → EHR (write) 3. Session records: Platform → EHR (write) 4. Diagnoses: EHR → Platform (read) 5. Medications: EHR → Platform (read) 6. Care plans: Bidirectional (merge strategy)
class DataSyncOrchestrator {
  private syncLog: SyncLog;
  private conflictResolver: ConflictResolver;
  
  async syncPatientData(patientId: string): Promise {
    const results = [];
    
    try {
      // 1. Pull updates from EHR (read-only data)
      const ehrUpdates = await this.pullFromEHR(patientId, [
        'Patient',        // Demographics
        'Condition',      // Diagnoses
        'MedicationStatement'  // Current meds
      ]);
      
      for (const resource of ehrUpdates) {
        await this.updateLocalResource(resource);
        results.push({ resource: resource.resourceType, success: true });
      }
      
      // 2. Push updates to EHR (therapy data)
      const localUpdates = await this.getUnsyncedLocalData(patientId);
      
      for (const update of localUpdates) {
        try {
          const fhirResource = this.transformToFHIR(update);
          await this.pushToEHR(fhirResource);
          await this.markSynced(update.id);
          results.push({ 
            resource: update.type, 
            success: true 
          });
        } catch (error) {
          results.push({ 
            resource: update.type, 
            success: false, 
            error 
          });
          // Add to retry queue
          await this.addToRetryQueue(update, error);
        }
      }
      
      // 3. Handle bidirectional resources (CarePlan)
      await this.syncCarePlan(patientId);
      
      // 4. Log sync operation
      await this.syncLog.record({
        patientId,
        timestamp: new Date(),
        results,
        success: results.every(r => r.success)
      });
      
      return {
        success: results.every(r => r.success),
        results
      };
      
    } catch (error) {
      await this.handleSyncFailure(patientId, error);
      throw error;
    }
  }
  
  private async syncCarePlan(patientId: string): Promise {
    // Get both versions
    const [ehrPlan, localPlan] = await Promise.all([
      this.getEHRCarePlan(patientId),
      this.getLocalCarePlan(patientId)
    ]);
    
    // Check for conflicts
    const conflict = this.detectConflict(ehrPlan, localPlan);
    
    if (!conflict) {
      // No conflict: simple merge
      const merged = this.mergeCarePlans(ehrPlan, localPlan);
      await this.updateBothSystems(merged);
    } else {
      // Conflict: apply resolution strategy
      const resolved = await this.conflictResolver.resolve({
        ehr: ehrPlan,
        local: localPlan,
        strategy: 'most-recent-wins' // or 'manual-review'
      });
      
      await this.updateBothSystems(resolved);
      await this.notifyOfConflict(patientId, conflict);
    }
  }
}

7.4 Cross-Platform Data Portability

Patients should own their health data and be able to move it between systems. The WIA-MENTAL-001 standard mandates comprehensive data export capabilities.

Data Export Formats

Format Use Case Technical Spec Completeness
FHIR Bundle (JSON) Import to other EHR/digital health apps HL7 FHIR R4, complete resource set 100% clinical data
PDF Report Human-readable summary for patients/providers PDF/A (archival format) Summary + visualizations
CSV Data analysis, spreadsheet import RFC 4180, UTF-8 encoding Tabular data only
JSON API Format Developer access, custom integrations JSON API v1.0 specification 100% including metadata

핵심 요점

복습 질문

  1. What is FHIR and how does it improve on earlier HL7 standards? Describe the key technical differences.
  2. Which FHIR resources are most relevant for mental health data exchange? Provide examples of how each is used.
  3. What are the integration challenges specific to Epic compared to other EHR vendors?
  4. How does the data sync orchestrator handle conflicts when the same resource is modified in both systems?
  5. Why is data portability important from both patient and regulatory perspectives?
  6. What compliance requirements apply when sharing data with EHR systems? How do Business Associate Agreements work?

한국 의료 인프라 매핑 (제7장)

한국 의료·바이오 인프라 — 보건복지부(MOHW)·식품의약품안전처(MFDS, 식약처)·국민건강보험공단(NHIS)·건강보험심사평가원(HIRA)·통계청(KOSTAT)·국립암센터·국립중앙의료원·국립재활원·6대 병원 (서울대·삼성·아산·세브란스·분당서울대·고려대)·KRIBB(한국생명공학연구원)·KRICT(한국화학연구원)·KFRI(한국식품연구원)·KIST·KAIST·POSTECH 협력. 「의료법」·「약사법」·「생명윤리 및 안전에 관한 법률」·「의료기기법」·「개인정보 보호법」·「국민건강보험법」·「응급의료에 관한 법률」 적용. KS X HL7 FHIR R5·KS X ISO/IEC 25237 (의료 비식별)·KCD-8 (한국표준질병분류)·SNOMED CT·LOINC·ICD-11·OMOP CDM v5.4·CDISC SDTM/ADaM·DICOM·KS X (한국 의료정보 표준) 한국 프로파일이 적용된다.