제6장

제6장: 동의·거버넌스·통합 — LIMS·HL7 FHIR·MIABIS와 개인정보

생체시료를 얼마나 쓸 수 있는지는 그 시료에 붙은 동의의 범위와, 그 기록을 읽어 낼 수 있는 시스템에 달려 있다. 이 장은 WIA-BIO-019의 윤리·법적 계층(§8)을 다루고, 표준을 따르는 바이오뱅크가 LIMS·임상 기록·연구 네트워크와 어떻게 연결되는지(§9.1.1, §9.2, §11.4–11.5)를 살펴본다.

제3장부터 제5장까지는 시료를 물리적이면서 디지털인 대상으로 다루었다. 시료는 위치와 품질 점수, 보관연속성(chain of custody) 기록을 가진 레코드였다. 그러나 이것만으로는 분양심의위원회가 가장 먼저 묻는 질문, 곧 이 시료를 이 목적으로, 이 요청자가, 이 나라에서 써도 되는가에 답할 수 없다. 그 답은 기증자의 동의와 그 동의를 둘러싼 윤리 승인, 그리고 기증자의 신원 정보가 데이터와 함께 어디까지 이동해도 되는지를 정하는 개인정보 규범 안에 있다. 이 장의 후반부는 시야를 바깥으로 넓힌다. WIA-BIO-019 구현체가 병원이 이미 운영하는 시스템들 사이에서 어디에 놓이는지, 그리고 그 레코드를 다른 바이오뱅크와 임상 시스템이 이해하는 교환 형식으로 어떻게 옮기는지를 다룬다.

이 장에서는 세 종류의 서술을 구분한다. 규범은 v1.0 명세서에서 온 내용이다. 관찰된 동작은 참조 TypeScript SDK(@wia/bio-019)의 소스에서 확인한 실제 동작이다. 이 책의 권고는 FHIR 매핑이나 동의 철회 절차처럼 v1.0이 비워 둔 부분을 채우는 합리적인 방법 가운데 하나를 제시한 것으로, 그렇게 표시한다. 권고는 표준의 요구사항이 아니다.

6.1 동의 모델과 Consent 레코드

6.1.1 포괄·특정·계층형 동의

명세서 §8.1.1은 세 가지 동의 모델을 정의한다. 포괄 동의(broad consent)는 기증 시점에 정해지지 않은 향후 연구까지 허용한다. 바이오뱅크는 어떤 과제가 시료를 요청할지 모르는 상태에서 먼저 수집하므로, 대부분의 바이오뱅크가 이 모델에 기댄다. 그 대가로 시료를 쓰는 과제마다 별도의 윤리 승인이 필요하고, 기증자는 언제든 철회할 권리를 가진다. 특정 동의(specific consent)는 명시된 연구 목적으로만 한정되며, 새로운 용도가 생기면 기증자에게서 다시 동의를 받아야 한다. 기증자의 통제권은 가장 크지만 바이오뱅크의 운신 폭은 가장 좁다. 계층형 동의(tiered consent)는 그 중간으로, 허락의 범위를 기증자가 고른다. 명세서는 네 단계를 예로 든다. (1) 이 연구에 한정, (2) 관련 연구, (3) 모든 보건 연구, (4) 상업적 연구를 포함한 모든 연구이다.

이 단계들은 포함 관계에 있다. 3단계를 수락한 기증자는 1·2단계도 수락한 것이며, 상업적 이용을 명시적으로 허용하는 것은 4단계뿐이다. 구현에서는 이 포함 관계가 중요하다. 아래에서 보듯 SDK에는 단계라는 개념이 아예 없고 목적 목록과 세 개의 예/아니오 플래그만 있다. 따라서 계층형 동의서는 기록할 때 이 기본 요소로 번역해야 한다.

§8.1.2는 동의 과정에서 기증자에게 알려야 할 사항을 열거한다. 바이오뱅크의 목적, 수집하는 시료 유형, 보관 기간, 잠재적 용도(연구·진단·상업), 위험과 이익, 개인정보 보호 조치, 철회권, 연락처, 다른 연구자와의 공유, 상업화 가능성, 결과 회신 여부가 그것이다. 문서화 요건도 함께 둔다. 서명된 동의서 또는 감사 추적이 남는 전자 동의, 동의서 양식의 버전 관리, 언어 접근성이다. §3.1.1은 수집 단계에서 이 목록의 핵심을 다시 요구하며, 모든 동의 관련 행위를 기록하도록 덧붙인다.

6.1.2 SDK의 동의 레코드

참조 SDK는 동의를 독립된 객체로 표현하고, 시료와는 DonorInfo.consentId를 통해서만 연결한다. 각 필드는 §8.1.2의 요소와 다음과 같이 대응한다.

동의 모델·요소(§8.1)SDK에서의 표현SDK가 검사하는 내용
동의 모델type: ConsentType.BROAD | SPECIFIC | TIERED없음. 참고용 값일 뿐이다
포괄 동의purposes: ['any'](또는 넓은 범주 목록)'any'는 모든 목적 문자열과 일치
특정 동의purposes: ['<단일 과제 또는 목적>']대소문자를 무시한 완전 일치
1단계 — 이 연구에 한정purposes에 과제 토큰 하나문자열 일치
2단계 — 관련 연구1단계 토큰 + 관련 연구 토큰문자열 일치
3단계 — 모든 보건 연구2단계 토큰 + 보건 연구 토큰문자열 일치
4단계 — 상업 포함 모든 연구purposes: ['any']와 commercialUse: true목적만 검사하며 상업 플래그는 읽지 않음
상업화 가능성commercialUse: booleanvalidateConsent가 검사하지 않음
다른 연구자와의 공유thirdPartySharing: boolean검사하지 않음
국외 이전(§8.2.1)internationalTransfer: boolean검사하지 않음
결과 회신returnResults: boolean검사하지 않음
동의서 버전 관리formVersion: string검사하지 않음
언어 접근성language: string검사하지 않음
보관 기간expiryDate?: Date이 날짜가 지나면 무효
철회권withdrawalDate?: Date, isValid: boolean둘 중 하나만 해당해도 무효
서명 동의서·전자 동의signature?: string, consentDate검사하지 않음

단계 행의 토큰 이름(study:…, related:…, health-research)은 이 책이 정한 관례이다. v1.0에는 목적 어휘가 정의되어 있지 않으므로 바이오뱅크마다 어휘를 정해 표준운영절차(SOP)에 적어 두어야 한다. 공통 어휘가 없으면 두 기관이 같은 기증자 의사를 서로 결코 일치하지 않는 방식으로 기록하게 된다.

6.1.3 validateConsent가 실제로 판정하는 것

validateConsent(consentId, purpose)의 절차는 짧다. 먼저 ID가 등록되어 있지 않으면 코드 B005(CONSENT_EXPIRED)로 BioBankingError를 던진다. "찾을 수 없음"과 "만료됨"은 다른 상황인데도 같은 코드를 쓴다. 다음으로 isValid가 거짓이거나, withdrawalDate가 있거나, 현재 시각이 expiryDate를 지났으면 예외 없이 false를 반환한다. 마지막으로 purposes가 비어 있지 않으면, 요청 목적과 대소문자 무시로 일치하거나 정확히 'any'인 항목이 하나 이상 있어야 한다. 이를 모두 통과하면 true를 반환한다.

이 함수를 실제 요청 앞에 세우기 전에 짚어야 할 결과가 세 가지 있다.

등록 쪽에도 빈틈이 있다. registerSample은 시료의 consentId가 등록된 동의를 가리키고 그 동의의 isValid가 거짓일 때만 시료를 거부한다. SDK가 한 번도 본 적 없는 동의 ID를 참조하는 시료는 아무 경고 없이 받아들여진다. 또 README 예제는 purpose 배열을 담은 consent 객체를 registerSample에 중첩해 넘기는데, 이런 구조는 types.ts에 존재하지 않는다. 실제 API에서는 동의를 registerConsent로 따로 등록하고 donor.consentId로 참조한다.

6.1.4 계층형 동의 예제와 호환성 래퍼

다음 코드는 2단계 계층형 동의를 기록하고, validateConsent를 얇은 래퍼로 감싼다. 래퍼는 SDK가 빠뜨린 부분을 보완한다. 빈 목적 목록을 거부하고, 세 허용 플래그를 검사하며, 거부를 타입이 있는 오류로 바꾼다. 효력이 없어진 동의에는 B005를, 동의가 포괄하지 않는 용도에는 B006을 쓴다. 이 구분은 기존 오류 코드 위에 이 책이 정한 관례이다.

import {
  BioBankingSDK, BioBankingError, BioErrorCode,
  Consent, ConsentType,
} from '@wia/bio-019';

// 이 책의 관례: §8.1.1의 네 단계를 누적되는 목적 토큰으로 표현한다.
const TIERS: Record<1 | 2 | 3 | 4, string[]> = {
  1: ['study:PRJ-2025-042'],
  2: ['study:PRJ-2025-042', 'related:cardiometabolic'],
  3: ['study:PRJ-2025-042', 'related:cardiometabolic', 'health-research'],
  4: ['any'],
};

interface UseContext {
  purpose: string;
  commercial: boolean;
  thirdParty: boolean;     // 시료나 데이터가 바이오뱅크 소속 기관 밖으로 나감
  international: boolean;  // 시료나 데이터가 국외로 나감
}

function recordConsent(sdk: BioBankingSDK, c: Consent): void {
  if (c.purposes.length === 0) {
    // SDK는 []를 "모든 목적"으로 취급한다(6.1.3 참조).
    throw new Error(`Consent ${c.consentId} has no purposes; refusing to register`);
  }
  sdk.registerConsent(c);
}

function assertCompatible(sdk: BioBankingSDK, c: Consent, use: UseContext): void {
  const inForce = c.isValid && !c.withdrawalDate &&
    !(c.expiryDate && new Date() > c.expiryDate);
  if (!inForce) {
    throw new BioBankingError(BioErrorCode.CONSENT_EXPIRED,
      `Consent ${c.consentId} is withdrawn, invalid or expired`);
  }
  const reasons: string[] = [];
  if (!sdk.validateConsent(c.consentId, use.purpose)) reasons.push('purpose');
  if (use.commercial && !c.commercialUse) reasons.push('commercialUse');
  if (use.thirdParty && !c.thirdPartySharing) reasons.push('thirdPartySharing');
  if (use.international && !c.internationalTransfer) reasons.push('internationalTransfer');
  if (reasons.length > 0) {
    throw new BioBankingError(BioErrorCode.CONSENT_NOT_COMPATIBLE,
      `Consent ${c.consentId} does not cover this use`, { reasons, use });
  }
}

const sdk = new BioBankingSDK();
const tier2: Consent = {
  consentId: 'CNS-456789', donorId: 'D-789012', type: ConsentType.TIERED,
  consentDate: new Date('2025-12-26T08:00:00Z'),
  purposes: TIERS[2],
  commercialUse: false, thirdPartySharing: true,
  internationalTransfer: false, returnResults: false,
  formVersion: 'ICF-v3.1', isValid: true, language: 'ko',
};
recordConsent(sdk, tier2);

이 동의에 대해 assertCompatible을 실행하면 아래와 같은 결과가 나온다. 처음 두 행은 SDK의 일치 규칙에서 곧바로 나온다. 나머지 세 행은 SDK가 하지 않는 일을 래퍼가 해 주는 경우이다.

요청된 용도validateConsent래퍼 판정
study:PRJ-2025-042, 국내, 비상업true허용
RELATED:CARDIOMETABOLIC(대문자), 협력 병원과 공유true(대소문자 무시)허용. 제3자 공유가 허락되어 있음
health-researchfalseB006, 사유 purpose(3단계 미허락)
related:cardiometabolic, 국외 반출trueB006, 사유 internationalTransfer
기증자 철회 이후의 모든 목적falseB005, 동의가 더 이상 유효하지 않음

SDK 밖에서 동의가 기록되는 맥락. 미국 공통규칙(Common Rule, 45 CFR 46)의 2018년 개정은 식별 가능한 생체시료를 이차 연구용으로 보관하기 위한 선택적 포괄 동의 경로를 새로 두었다. EU의 GDPR은 동의를 연구 목적 처리의 여러 적법 근거 가운데 하나로만 본다. WIA 레코드는 두 상황을 모두 담을 수 있다. 다만 적법 근거 자체는 동의서 버전이나 연결 문서 등에 동의와 함께 저장해야 하며, 암묵적으로 남겨 두어서는 안 된다.

6.2 동의 철회와 그 파급 효과

§8.1.1은 기증자가 "언제든 철회할 수 있다"고 보장한다. 철회는 결과를 수반하는 사건이다. 냉동고 안의 시료, 거기서 나온 분주물, 아직 심사 중인 분양 요청, 이미 발송된 시료마다 각각 결정이 필요하다. v1.0은 각 경우에 무엇을 해야 하는지 정하지 않는다. SDK는 시료를 등록할 때와 호출자가 validateConsent를 부를 때만 동의를 확인한다. 분양 요청을 처리하는 메서드가 없어 SampleRequest는 타입으로만 존재하며, 요청이 심사 단계를 거치는 동안 동의를 다시 확인하는 코드도 없다. 재고 조회와 분주물 레코드는 동의를 아예 보지 않는다. 따라서 철회는 의도적으로 전파해야 한다.

실제 철회는 한 가지 모양이 아니다. 많은 동의서가 "더 이상 사용하지 말고 남은 시료는 폐기"와 "더 이상 사용하지 말되 이미 분석에 쓰인 결과는 유지" 가운데 하나를 고르게 하며, 새로운 연락만 거부하는 선택지를 두기도 한다. 바이오뱅크의 SOP는 자기 동의서가 제시하는 선택지를 나열하고 각각을 구체적인 조치에 대응시켜야 한다. 합리적인 전파 절차(이 책의 권고)는 다섯 단계로 이루어진다.

  1. 철회를 기록한다. isValid: false와 withdrawalDate를 넣어 동의를 다시 등록한다. 이 순간부터 validateConsent는 모든 목적에 대해 false를 반환한다.
  2. 영향받는 시료를 찾는다. donor.consentId가 일치하는 모든 시료를 고른다. 분주물에는 기증자나 동의 필드가 따로 없고 parentSampleId나 모시료의 aliquots[] 배열을 통해서만 닿을 수 있으므로, 검색은 계보를 따라 내려가야 한다.
  3. 분양을 막는다. 영향받는 시료가 포함되어 있고 상태가 pending·under_review·approved인 모든 SampleRequest를 분양심의위원회로 되돌린다. 요청은 rejected로 처리하거나 영향받지 않는 시료만 남기도록 줄인다. 위원회 기록에는 B005를 명시한다.
  4. 시료를 처리한다. 기증자가 폐기를 요청했다면 통상의 폐기 SOP에 따라 폐기하고, 상태를 destroyed로 바꾼 뒤 CustodyAction.DESTRUCTION 이벤트를 추가한다. 그러면 언제 누가 폐기했는지가 보관연속성 기록에 남는다. 기존 결과의 유지만 허락했다면 시료를 남겨 두되 분양 불가로 표시한다.
  5. 수령자에게 알린다. 이미 연구자에게 fulfilled된 시료는 물질이전계약(MTA)의 적용을 받는다. 바이오뱅크는 수령자에게 통보하고, MTA에는 미사용 시료를 반환할지 폐기할지가 적혀 있어야 한다.

2단계와 4단계는 지금 있는 SDK 메서드로 작성할 수 있다.

import { BioBankingSDK, Consent, CustodyAction, SampleStatus } from '@wia/bio-019';

function propagateWithdrawal(
  sdk: BioBankingSDK, c: Consent, destroy: boolean, operator: string,
): string[] {
  sdk.registerConsent({ ...c, isValid: false, withdrawalDate: new Date() });

  // limit 없이 호출한 queryInventory()는 SDK가 가진 모든 시료를 돌려준다.
  const affected = sdk.queryInventory({})
    .filter((s) => s.donor.consentId === c.consentId);

  const touched: string[] = [];
  for (const s of affected) {
    touched.push(s.id, ...(s.aliquots ?? []).map((a) => a.id));
    if (destroy) {
      sdk.addCustodyEvent(s.id, {
        action: CustodyAction.DESTRUCTION, operator,
        location: s.location.fullLocation ?? 'BIOBANK',
        notes: `Consent ${c.consentId} withdrawn; destroyed per donor request`,
      });
      sdk.updateSample(s.id, {
        status: SampleStatus.DESTROYED,
        aliquots: (s.aliquots ?? []).map((a) => ({ ...a, status: SampleStatus.DESTROYED })),
      });
    } else {
      sdk.updateSample(s.id, { notes: `HOLD: consent ${c.consentId} withdrawn` });
    }
  }
  return touched; // 요청 재심사(3단계)와 수령자 통보(5단계)의 입력으로 쓴다
}

이 코드의 모양은 SDK의 두 가지 성질에서 나온다. 첫째, queryInventory의 availableOnly 필터는 depleted 시료만 제외하므로, 폐기된 시료도 "분양 가능" 결과에 계속 나타난다. 재고 화면은 상태로도 걸러야 한다. 둘째, SDK에는 동의 보류 플래그가 없다. 위 코드는 유지하는 경우 보류 사실을 notes에 적는데, 사람은 읽을 수 있어도 질의로 걸러 낼 수는 없다. 운영 시스템은 시료 ID를 키로 하는 별도의 보류 테이블을 두고 모든 반출 전에 확인해야 한다.

6.3 윤리 심의와 분양 거버넌스

동의는 기증자가 무엇을 허락했는지를 정한다. 윤리 심의와 분양 거버넌스는 특정 용도가 그 허락 범위 안에 있으면서 과학적·윤리적으로도 타당한지를 판단한다. §8.2.1은 연구윤리심의위원회(IRB) 또는 윤리위원회의 승인, 연 단위 갱신, 중대한 변경에 대한 변경 승인을 요구한다. 또 심의를 어렵게 만드는 고려 사항으로 취약 집단, 미성년자(부모 동의 필요), 유전 정보의 민감성, 문화·종교적 요인, 국외 이전을 든다.

미성년자는 장기적인 문제를 따로 안고 있다. 부모 동의로 아이의 시료를 보관한 바이오뱅크는 언젠가 스스로는 아무것에도 동의한 적 없는 성인의 시료를 보유하게 된다. 많은 거버넌스 체계는 기증자가 성년이 되면 본인의 동의를 다시 받거나, 적어도 그 시점에 대한 서면 정책을 갖추도록 기대한다. v1.0은 이 문제를 다루지 않지만 Consent 레코드로 뒷받침할 수는 있다. 부모 동의의 expiryDate를 기증자의 성년 도달일로 설정하면, 조용히 이어지는 대신 새로운 결정이 강제된다.

§8.2.2는 재고와 요청자 사이에 서는 분양심의위원회를 규정한다. 위원회는 요청을 검토하고, 과학적 가치를 평가하며, 동의와의 부합을 확인하고, 물질이전계약을 승인한다. 판단 기준은 제안의 과학적 수준, 실현 가능성, 요청 과제 자체의 윤리 승인, 기증자 동의와의 부합, 시료 가용성이다. 각 기준은 데이터 모델에 흔적을 남긴다.

위원회 판단 기준(§8.2.2)WIA 레코드의 근거자동화 가능 여부
제안의 과학적 수준projectTitle, purpose. 연구계획서 자체는 레코드 밖에 첨부불가 — 사람의 판단
실현 가능성현재 부피 대비 samples[].volumeRequested, 품질 점수(제3장)일부 — 부피·품질 사전 점검
요청 과제의 윤리 승인ethicsApproval(API의 ethics_approval)존재 여부는 가능, 유효성은 발급 IRB 확인 필요
기증자 동의와의 부합각 시료의 Consent와 purpose 대조가능 — 6.1.4의 래퍼 사용
시료 가용성SampleStatus, 보류 테이블, RequestedSample.permanent/returnDate가능
이전 조건mta 참조, approvedBy, approvalDate불가 — 양 기관의 서명

좋은 방식은 "가능" 행을 사전 점검으로 자동화해, 요청이 under_review에 들어갈 때 실행하는 것이다. 점검 결과는 요청에 메모로 붙어 위원회가 심의 전에 보게 된다. 사전 점검이 스스로 요청을 approved로 옮겨서는 안 된다. 제5장의 상태 기계는 그 전이에 사람의 결정을 두었고, 결정한 위원회의 신원은 approvedBy에 남는다.

물질이전계약은 동의의 제한이 계약상의 의무로 바뀌는 자리이다. MTA에는 최소한 허용된 목적을 다시 적고, thirdPartySharing이 거짓이면 재이전을 금지하며, 재식별 시도를 금지하고, 미사용 시료의 처리(returnDate까지 반환 또는 폐기)를 명시하고, 이후 철회 통보가 오면 따르도록 수령자에게 의무를 지워야 한다. SDK는 mta에 참조 문자열만 저장하므로, 서명된 문서는 문서관리 시스템에 두고 그 식별자를 여기에 기록한다.

6.4 비식별화와 개인정보 법제

6.4.1 식별 가능성의 세 수준

§8.3.1은 세 수준을 구분한다. 익명화(anonymized) 시료는 기증자로 되돌아가는 연결이 없으며 복원할 수도 없다. 가명화(코드화)(coded) 시료는 코드로 연결되어 있고, 그 키는 따로 보관된다. 식별 가능(identifiable) 시료에는 직접 식별자가 붙어 있다. 명세서는 키 접근을 엄격히 통제하는 코드화 시료를 권장하며, 코드 체계도 정한다. SAM-XXXXXX 형식의 무작위 영숫자 ID를 쓰고, 날짜나 일련번호 같은 정보를 넣지 않으며, 기증자–시료 연결은 별도 데이터베이스에 둔다.

코드화가 권장되는 이유는 익명화가 양방향으로 되돌릴 수 없기 때문이다. 연결이 사라지면 철회 요청을 이행할 수 없고, 임상적으로 중요한 결과를 회신할 수도 없으며, 시료에 새로운 추적 데이터를 덧붙일 수도 없다. 식별 가능한 상태로 보관하면 반대로 데이터 사본 하나하나가 노출 위험이 된다. 코드화 설계는 기증자를 대신해 조치할 능력을 유지하면서도 연구자가 기증자가 누구인지 결코 보지 못하게 한다.

WIA 데이터 모델은 이 설계에 맞추어져 있다. DonorInfo에는 비식별화된 donorId, 나이, 성별, 민족, 수집 기관, 병력, 복용 약물, 공복 여부가 있고, 이름·생년월일·주소·국가 식별번호는 없다. donorId와 실제 인물의 대응은 연결 데이터베이스에만 있으며, 6.5의 아키텍처는 이를 별도의 키 금고 뒤에 둔다. 다만 두 가지를 주의해야 한다. 첫째, SDK의 generateSampleId()는 ID를 SAM-<Date.now()>-<random> 형태로 만들어 밀리초 단위 타임스탬프를 넣는다. 반면 §8.3.1은 날짜를 넣지 말라고 요구한다. 이 차이는 제3장에서 다루었는데, 여기서 중요한 까닭은 시간에서 유도된 ID를 읽을 수 있는 사람이면 누구나 수집 시점을 알 수 있기 때문이다. 둘째, 이름이 없어도 나이·성별·수집 기관과 medicalHistory의 희귀 진단명이 결합하면 한 사람을 특정할 수 있다. 재고 조회는 donorAgeRange와 donorSex 필터를 지원하므로, 건수를 보여 주는 연구 포털은 좁은 조건의 질의에 "시료 1건"을 그대로 보여 주지 말고 작은 셀을 억제해야 한다.

6.4.2 GDPR

§8.3.2는 EU 요건을 요약한다. 적법한 처리 근거(동의 또는 공익), 데이터 최소화, 보관 제한, 보안 조치, 그리고 열람·정정·삭제·처리 제한·이동권 같은 정보주체의 권리이다. 유전 데이터와 건강 데이터는 특수 범주 데이터로서 명시적 동의나 상당한 공익이 필요하다고도 적는다. 이는 GDPR 제9조의 특수 범주에 해당한다. 실무에서는 세 가지를 더 알아 두면 좋다.

6.4.3 HIPAA

§8.3.3은 미국 HIPAA 프라이버시 규칙을 다룬다. 보호 대상 건강정보(이름, 주소, 날짜, 전화번호, 이메일, 사회보장번호 등)는 연구에 쓰기 전에 제거하거나 코드화해야 한다. 규칙은 두 가지 비식별화 방법을 둔다(45 CFR 164.514). 세이프 하버(Safe Harbor) 방법은 열거된 식별자 18종을 제거하고, 남은 정보로 개인을 식별할 수 있다는 사실을 해당 기관이 실제로 알지 못할 것을 요구한다. v1.0이 언급하지 않는 전문가 판정(Expert Determination) 방법은 자격을 갖춘 전문가의 문서화된 평가에 의존한다. 식별 가능과 비식별 사이에는 제한적 데이터 세트(Limited Data Set)가 있다. 날짜와 일부 지리 정보(시·주·우편번호 등)를 남길 수 있지만 데이터 이용 계약(DUA)을 맺어야만 제공할 수 있다.

WIA 레코드에서 실무상 핵심은 날짜이다. collectionDate는 완전한 타임스탬프인데, 세이프 하버는 개인과 관련된 날짜 가운데 연도보다 세밀한 모든 요소를 식별자로 본다. 따라서 세이프 하버 기준으로 내보내는 데이터 세트는 collectionDate를 연도 단위로 낮추거나 등록 후 경과 일수 같은 간격으로 바꾸어야 한다. 그렇지 않으면 DUA를 갖춘 제한적 데이터 세트로 취급해야 한다. §9 재고 응답에는 collection_date와 storage_duration_days가 함께 들어 있다. 간격이라고 저절로 안전해지지는 않는다. 알려진 내보내기 날짜에서 storage_duration_days를 빼면 수집일이 정확히 되살아난다. 두 필드를 함께 거칠게 만들거나, 간격의 기준점을 그 자체로는 달력 날짜가 아닌 기증자별 기준점으로 잡아야 한다.

한국의 맥락(개괄). 국내에서 인체유래물과 바이오뱅크는 「생명윤리 및 안전에 관한 법률」(생명윤리법)의 규율을 받는다. 이 법은 인체유래물과 관련 정보를 수집·보존하고 제공하는 기관을 인체유래물은행이라 부른다. 기증에는 서면 동의를 요구하고, 기관생명윤리위원회(IRB에 해당하는 국내 기구)의 심의를 요구하며, 제3자 제공과 폐기에 관한 규칙도 둔다. 개인정보 전반은 「개인정보 보호법」이 규율하며, 이 법에는 과학적 연구 등을 위한 가명정보 처리에 관한 규정이 있다. 구체적인 개설·등록 의무, 동의서 기재 사항, 제공 요건은 법률과 시행령·시행규칙에 정해져 있고 수시로 개정된다. 국내 바이오뱅크는 현행 조문을 법률 자문과 함께 확인해야 한다. 이 책은 조문 번호를 인용하지 않는다.

6.5 LIMS 통합

§9.1.1은 실험실 정보관리 시스템(LIMS)이 바이오뱅크에 제공해야 할 핵심 기능을 네 묶음으로 나열한다. 시료 추적은 고유 ID 부여, 바코드 생성, 냉동고·랙·박스·위치까지의 위치 추적, 분주물 계보이다. 재고 관리는 실시간 가용성, 재고 부족 경보, 만료 추적, 품질 플래그이다. 데이터 관리는 비식별 기증자 인구학 정보, 수집 메타데이터, 처리 파라미터, 품질 지표, 보관연속성이다. 업무 흐름 관리는 요청 처리, 시료 반출, 배송 추적, 보고서 생성이다.

이 기능은 거의 모두 제3–5장의 WIA 모델에 대응 요소가 있다. 그래서 모든 기관이 답해야 할 설계 질문이 생긴다. WIA-BIO-019가 곧 LIMS인가, 아니면 LIMS 옆에 놓이는가? 대부분의 병원에서 답은 "옆"이다. 기존 LIMS가 이미 실험대 업무와 스캐너, 라벨 프린터를 돌리고 있기 때문이다. WIA 계층은 교환과 보증의 경계로 보는 것이 가장 알맞다. 다른 시스템에서 시료가 등록되고 연구자의 요청이 들어오는 안정적이고 표준화된 API이며, 보관연속성 해시가 계산되고 동의가 집행되는 자리이다. LIMS는 실험대 업무의 기준 시스템으로 남고, 상태 변화를 보관연속성 이벤트로 WIA 계층에 밀어 넣는다.

WIA-BIO-019 바이오뱅크의 통합 아키텍처 연구 포털 카탈로그, 분양 요청 EHR / FHIR 서버 임상 데이터, 검사 오더 WIA-BIO-019 API 게이트웨이 /samples · /inventory · /requests 동의 검사 · 보관연속성 해시 · 감사 LIMS 실험대 업무, 스캐너, 라벨 프린터, 냉동고 키 금고 기증자 ↔ donorId 연결, 동의서 원본 코드화 데이터만 FHIR Specimen 보관연속성 이벤트 재식별 전용 (철회, 재연락)
그림 6-1. 참조 통합 아키텍처(이 책의 권고). 다른 모든 시스템과 통신하는 것은 게이트웨이뿐이다. 연구자는 코드화 데이터만 보며, 키 금고는 기증자 신원이 필요한 조치에 한해 별도 인가를 거쳐서만 조회된다.

그림 6-1은 세 가지 설계 선택을 드러낸다. 첫째, 연구 포털은 LIMS를 직접 읽지 않는다. 모든 카탈로그 질의는 GET /api/v1/inventory를 거치므로, 작은 셀 억제와 동의 필터링이 한곳에서 일어난다. 둘째, 키 금고는 요청 경로에 있지 않다. 게이트웨이는 그 자체로 기록되고 인가되는 작업을 통해서만 기증자 신원을 요청할 수 있다. 대표적인 경우는 철회 처리(6.2)와, returnResults가 참일 때 임상적으로 조치가 필요한 결과를 알리기 위한 재연락이다. 셋째, EHR 연결은 양방향이지만 좁다. 임상 시스템에서 오더와 수집 이벤트가 들어오고 시료 상태가 되돌아갈 수 있지만, 연구에 쓰이는 임상 데이터는 EHR에서 노출되는 대신 코드화 공간으로 끌어와 쓴다.

바코드와 스캐너 연동은 경계의 LIMS 쪽에 속한다. 스캐너가 라벨(제3장에서 본 Code128 또는 DataMatrix)을 읽으면 LIMS가 이를 시료 ID와 위치로 해석하고, 그 결과로 생긴 이동을 보관연속성 이벤트로 보낸다. WIA 등록 응답은 라벨 부착용 바코드 이미지(§9 API의 barcode)를 돌려준다. LIMS가 이미 라벨을 출력하는 기관이라면 두 시스템이 같은 식별자를 인코딩하는지 확인해야 한다. 한 튜브에 서로 다른 바코드 두 개가 붙는 것은 시료 뒤바뀜의 잘 알려진 원인이다.

이 연결들의 보안 체계, 곧 인증된 호출, 전송 중·저장 시 암호화, 다중 인증을 갖춘 역할 기반 접근, 감사 기록은 제4장에서 API와 함께 설명했으므로 여기서 되풀이하지 않는다. 통합에 고유한 점은 하나이다. 연결된 시스템마다 자기 자격 증명과 역할을 가져야 한다. 서비스 계정을 공유하면 감사 기록이 LIMS의 반영과 포털의 질의를 구분하지 못한다.

6.6 데이터 표준: HL7 FHIR·SPREC·MIABIS·BRISQ

§9.2는 네 가지 상호운용 표준과 네 가지 데이터 형식을 든다. 형식은 API 교환용 JSON, 대량 데이터용 CSV/TSV, HL7 메시지용 XML, 보고서와 라벨용 PDF이다. §11.4는 명세서가 염두에 둔 판을 밝힌다. SPREC v2.0(2015), MIABIS v2.0(2016), BRISQ(2011), 그리고 판이 명시되지 않은 HL7 FHIR이다. 네 표준은 각기 다른 질문을 다룬다.

v1.0은 이 표준들의 이름만 들 뿐, 자기 필드를 어느 표준에도 매핑하지 않는다. 아래 표는 핵심 Sample 필드에 대해 이 책이 제안하는 매핑이다. FHIR 열은 따로 밝히지 않는 한 R4의 Specimen 리소스를 기준으로 한다. MIABIS 열은 MIABIS Core와 그 뒤에 나온 시료 수준 구성요소의 속성 개념을 쓴다. 정확한 속성 이름은 릴리스마다 다르므로 구현자는 목표 릴리스와 대조해야 한다.

WIA Sample 필드HL7 FHIR(이 책의 매핑)MIABIS 개념
id(SAM-XXXXXX)Specimen.identifier(system = 바이오뱅크 네임스페이스)Sample ID
type(SampleType)Specimen.type. 열거값 14종을 사용하는 용어 체계로 옮기는 코드표 필요Material type
donor.donorIdSpecimen.subject → 가명 PatientSample donor ID
donor.sex, donor.agePatient.gender. 생년월일은 재식별 위험이 있으므로 수집 시 나이는 확장이나 관찰 리소스로 표현Sex, 나이(컬렉션 수준에서는 나이 범위)
collectionDateSpecimen.collection.collected[x]Sampling time
volume, volumeUnitSpecimen.collection.quantity(최초), Specimen.container.specimenQuantity(현재)—(핵심 속성 아님)
storageConditionSpecimen에 전용 요소가 없어 확장 사용. 제품형 물질에는 BiologicallyDerivedProduct.storage.temperature가 있음Storage temperature
location튜브는 Specimen.container.identifier, 냉동고·랙·박스는 로컬 확장—(기관 내부 정보)
status(SampleStatus)Specimen.status(available / unavailable / unsatisfactory / entered-in-error). 거칠어서 WIA의 10개 상태를 묶어야 함—(컬렉션 수준의 가용성)
parentSampleIdSpecimen.parent—
quality(QualityMetrics)specimen이 해당 시료를 가리키는 Observation 리소스—
donor.consentId별도의 Consent 리소스(상태, 목적·기간을 담은 provision)컬렉션 수준의 이용·접근 조건
riskGroup핵심 요소 없음, 확장—

매핑의 몇 가지 선택은 설명이 필요하다. BiologicallyDerivedProduct는 이식용 세포·조직 제품이나 제대혈 단위처럼 환자에게 쓰일 물질을 위한 FHIR 리소스이다. 제대혈은행이나 세포치료 은행에는 알맞은 대상이지만, 연구용 생체시료에는 Specimen이 더 자연스러워 표의 중심에 두었다. status 행에서는 정보가 사라진다. FHIR의 시료 상태는 생애주기의 위치가 아니라 사용 가능 여부를 나타내므로, stored·retrieved·returned는 모두 available이 되고 depleted와 destroyed는 모두 unavailable이 된다. 상대 기관이 생애주기의 세부를 필요로 한다면 핵심 필드에 뜻을 덧씌우지 말고 로컬 확장으로 보낸다.

매핑은 비식별화도 지켜야 한다. Specimen.subject는 donorId와 최소한의 인구학 정보만 담은 가명 Patient 리소스를 가리켜야 하며, 병원의 임상 Patient 레코드를 가리켜서는 안 된다. 바이오뱅크의 FHIR 엔드포인트와 EHR이 같은 서버를 쓴다면, 코드화 데이터가 실수로 신원과 다시 결합될 가능성이 가장 큰 곳이 바로 여기이다.

직렬화는 제3장에서 정한 관례를 따른다. 전송 형식은 snake_case, SDK는 camelCase를 쓰고, 단위는 명시하며, 날짜는 UTC 기준 ISO 8601이다. FHIR 어댑터는 같은 레코드의 세 번째 표현이 되므로, SDK 객체로부터 한곳에서 생성해야 한다. 손으로 쓴 템플릿은 시간이 지나면 어긋나기 쉽다.

6.7 WIA 생태계 연결과 배치 토폴로지

§11.5와 README는 관련 WIA 표준 네 가지를 든다. WIA-INTENT는 의도 기반 인터페이스를 제공하며, README는 그 역할을 의도 기반 시료 질의로 설명한다. WIA-OMNI-API는 범용 API 게이트웨이이다. WIA-HEALTH는 의료 데이터 표준과 통합을, WIA-SOCIAL은 협업 연구 네트워크를 다룬다. v1.0은 이 관계의 이름만 두고 서로 간의 인터페이스는 정의하지 않는다. 따라서 지금의 통합은 다른 표준 위에 만든 시스템이 §9 REST API를 호출하는 형태이며, 공동 프로토콜은 아직 없다.

PHASE-4 통합 문서에는 네 가지 참조 배치 토폴로지를 담은 비규범적 부속서 J가 있다. (이 문서의 머리말은 WIA-BIO-018로 잘못 표기되어 있으며, 제4장에서 밝혔듯 여기서는 맥락 자료로만 쓴다.) 이 토폴로지는 배치 단위가 보통 병원이나 지역 거점인 바이오뱅크 네트워크에 잘 들어맞는다.

토폴로지(PHASE-4 부속서 J)구성바이오뱅크 시나리오연결 키의 위치
단일 테넌트 엣지기관당 런타임 하나, 공유 상태 없음자기 카탈로그를 공개하는 단일 병원 바이오뱅크같은 기관의 로컬 키 금고
다중 테넌트 게이트웨이공유 런타임 하나가 격리된 여러 테넌트를 처리여러 소규모 컬렉션의 API를 운영하는 지역 거점테넌트마다 금고 하나, 거점에는 두지 않음
연합 메시피어 런타임들이 디렉터리 서비스에 매니페스트를 게시카탈로그를 공유하는 국가 또는 질환별 네트워크각 회원 기관이 따로 보관, 디렉터리에는 신원 없음
에어갭 배치실시간 연결 없이 서명된 배치를 오프라인으로 이동보안 등급이 높거나 규제기관이 제한하는 컬렉션에어갭 내부

맨 오른쪽 열은 부속서 J의 내용이 아니라 이 책의 권고이며, 하나의 원칙을 따른다. 재식별은 동의를 받은 곳에서만 가능해야 한다. 연합 카탈로그는 어떤 회원 기관이 특정 진단을 받은 기증자의 혈장 시료 40건(예시 수치)을 가지고 있다고 연구자에게 알려 줄 수는 있지만, 그 기증자가 누구인지는 누구에게도 알려 줄 수 없어야 한다. 같은 원칙이 다중 테넌트의 경우도 제약한다. 여러 병원의 API를 운영하는 거점이 그들의 연결 테이블이 한데 모이는 장소가 되어서는 안 된다.

같은 문서의 부속서 I는 배치마다 서명된 프로파일 매니페스트를 게시하자고 제안한다. 매니페스트에는 요구사항별로 완전 지원, 부분 지원(사유 포함), 제외(근거 포함)를 적으며, 토폴로지가 바뀌면 새 매니페스트가 필요하다. 바이오뱅크 네트워크에서는 회원 기관이 무엇을 지원하는지 정직하게 밝히는 실용적인 방법이 된다. 예를 들어 어떤 기관은 6.1.4의 동의 플래그 검사를 집행하고, 다른 기관은 아직 철회를 자동으로 전파하지 못할 수 있다. 제7장에서 이 매니페스트를 적합성 증빙 패키지의 일부로 다시 다룬다.

장 요약