제7장
WIA-BIO-018이 요구하는 여섯 가지 필수 구성요소를 실제로 돌아가는 서비스로 만드는 방법을 다룬다. 전자동의(eConsent), 위변조를 드러내는 감사 추적, 유전체 데이터의 개인정보 보호 통제, 감사관이 실제로 인용할 규정과의 대응, 그리고 연구기관이 이미 운영하는 시스템과의 연동이 그 내용이다.
앞 장들은 BIO-018이 무엇을 요구하는지를 설명했다. 윤리 원칙, 동의와 심의의 규칙, 데이터 모델, SDK, 심의 프로토콜이 그것이다. 이 장은 그것을 만드는 일을 다룬다. 명세 §8.1은 준수 시스템이라면 여섯 가지 구성요소를 "반드시 포함해야 한다"고 적지만, 각 구성요소의 정의는 한 줄씩뿐이다. 구성요소끼리 어떻게 주고받는지, 감사 기록에 무엇이 들어가는지, 동의서 버전을 어떻게 관리하는지, 어느 필드가 어느 규정을 충족시키려는 것인지는 적혀 있지 않다. 이런 결정은 구현자의 몫이고, 점검자가 실제로 확인하는 것도 바로 이 결정들이다.
아래에서 명세를 넘어서는 내용은 모두 이 책의 권고임을 밝혀 둔다. 코드 식별자는 api/typescript/src/의 참조 TypeScript 소스에서 가져왔다. README에 설치 명령이 있지만 이 책은 이 소스가 npm 패키지로 공개되어 있다고 가정하지 않으므로, 예제는 로컬 경로에서 가져온다. 이 소스에 의존하기 전에 알아야 할 사실이 두 가지 더 있다. 배포된 그대로의 소스는 엄격 모드 tsc로 컴파일되지 않는다(두 파일 모두에 중복된 export 블록이 있고, 유전자 편집 경로가 자신의 반환 타입에 없는 'revise' 값을 돌려준다). 또 몇몇 기본값은 운영 환경에서 안전하지 않다. 소스를 저장소에 복사해 들여오고(vendoring), 결함을 고치고, 인증받은 버전을 고정해야 한다.
여섯 가지 필수 구성요소는 동의 관리, IRB 제출, 위험 평가, 개인정보 보호, 감사 추적, 보고이다. 명세에 충실하면서 가장 단순한 아키텍처는 각 구성요소를 자기 데이터와 좁은 인터페이스를 가진 서비스로 두고, 공통 규칙 하나를 더하는 것이다. 윤리적으로 의미 있는 결정을 내리거나 기록할 때마다 모든 구성요소는 감사 추적에 이벤트를 보낸다. 이렇게 나누는 목적은 규모가 아니라 책임 소재이다. 점검자가 참여자 P-12345가 왜 등록되었는지 물을 때, 답은 거대한 단일 시스템의 상태를 복원해서가 아니라 소유자가 분명한 소수의 기록에서 나와야 한다.
| 구성요소(§8.1) | 소유하는 기록 | 주요 SDK 호출 또는 규칙 | 감사 추적으로 보내는 이벤트 |
|---|---|---|---|
| 1. 동의 관리 | InformedConsent, ComprehensionAssessment, 버전·언어별 동의서 양식 | validateInformedConsent | 양식 버전 승인, 동의 취득, 동의 검증, 재동의, 철회 |
| 2. IRB 제출 | IRBProtocol, IRBSubmission, 결정과 만료일 | submitIRBProtocol(심의 수준 배정) | 제출, 수준 배정, 상태 변경, 결정, 변경 신청 |
| 3. 위험 평가 | RiskBenefitAnalysis, GeneEditingDecision | assessEthicalRisk, performRiskBenefitAnalysis, evaluateGeneEditingEthics | 점수 산출(입력 해시 포함), 사람의 재정의 |
| 4. 개인정보 보호 | GeneticData, 가명화 키, 접근 권한 | 보호 수준 1~4(§6.1), RBAC | 접근 부여·회수, 데이터 반출, 재식별 요청 |
| 5. 감사 추적 | 추가 전용 이벤트 로그 자체 | 해시 체인, 보존 | 체인 머리의 주기적 외부 고정(앵커) |
| 6. 보고 | AdverseEvent, ProtocolDeviation, AuditResult, 경과 보고 | 관할별 보고 기한 | 사례 기록, 보고 발송, 접수 확인 |
아래 그림은 주요 흐름을 보여 준다. 프로토콜과 승인된 동의서가 먼저 있고, 유효한 동의가 등록의 관문이 되며, 등록 사실은 임상시험 관리 시스템과 자료 수집 시스템에 통지된다. 안전성 사례는 보고 구성요소로 흘러가고, 여섯 구성요소 모두가 감사 추적에 기록한다.
[연구팀]
|
v
(2) IRB 제출 ---- 호출 ----> (3) 위험 평가
IRBProtocol, IRBSubmission assessEthicalRisk, performRiskBenefitAnalysis,
| evaluateGeneEditingEthics
| 승인된 프로토콜 + 승인된 동의서 버전
v
(1) 동의 관리 <---- [참여자]
InformedConsent, validateInformedConsent
|
| 유효한 동의 => 등록 이벤트
+------------------> CTMS / EDC (등록, 증례기록서 개방)
+------------------> (4) 개인정보 보호
GeneticData, 키 보관, 암호화, RBAC
[기관 담당자] --------> (6) 보고
AdverseEvent, ProtocolDeviation, 지속 심의
(1) (2) (3) (4) (6) ---- 추가 전용 이벤트 ----> (5) 감사 추적
해시 체인, 버전 기록, 외부 앵커
세 가지 의존 관계는 명시적으로 설계해야 한다. 첫째, 동의 관리는 IRB가 어느 프로토콜에 대해 어느 동의서 버전을 승인했는지 알아야 한다. 그래야 승인되지 않은 버전에 대한 서명을 거부할 수 있다. 이 조회는 동의 기록에 딸려 저장된 양식 사본이 아니라 IRB 제출 서비스로 가야 한다. 둘째, 등록은 다른 시스템이 주기적으로 확인하는 플래그가 아니라 반응하는 이벤트여야 한다. 참여자는 승인되고 만료되지 않은 프로토콜 기준으로 검증을 통과한 동의를 동의 서비스가 기록했을 때에만 "등록됨"이 된다. 셋째, 위험 평가 서비스는 연구별 상태를 갖지 않아야 한다. 입력을 받아 점수를 돌려주고, 입력과 결과를 기록하는 것은 호출한 쪽이다. 그래야 채점 규칙을 교체할 수 있고, 규칙이 바뀌어도 과거 기록은 그대로 남는다.
단일 기관이라면 구성요소별로 스키마를 나눈 데이터베이스 하나로 시작해도 충분하다. 중요한 것은 경계가 코드와 권한 양쪽에 존재하는 것이다. 보고 서비스가 동의 기록을 쓸 수 있어서는 안 되고, 누구도 감사 이벤트를 수정하거나 삭제할 수 있어서는 안 된다.
전자동의는 표준이 참여자를 직접 만나는 지점이며, 점검자가 가장 자주 표본을 뽑는 구성요소이다(§9.2는 매월 동의 표본을 검토하도록 한다). 여기서 네 가지 설계 문제가 되풀이된다.
동의 기록에는 version 필드가 있다(§8.3.1 예시에서는 "3.1"). 이 필드는 정확한 의미를 가져야 한다. 참여자가 본 바로 그 문구와, 그것이 제시된 언어이다. 양식은 프로토콜·버전·언어를 키로 하는 불변 객체로 저장하고, 그것을 승인한 IRB 결정과 연결한다. 문구가 조금이라도 바뀌면 새 버전이 되고, 사용 전에 승인을 받아야 한다. 새 버전이 승인되면 시스템은 영향받는 사람을 가려내야 한다. 아직 선별 중인 참여자는 새 양식으로 넘어가고, 이미 등록된 참여자는 변경 내용이 계속 참여할 의사에 영향을 줄 수 있는 중요한 새 정보인지에 따라 재동의가 필요할 수 있다. 이 판단은 IRB의 몫이므로, 시스템은 문구 차이에서 추론하지 말고 해당 버전에 대한 명시적 결정으로 기록해야 한다.
language 필드에는 자유 형식의 언어 이름이 아니라 en, ko, es-MX 같은 BCP 47 언어 태그(RFC 5646)를 넣는다. 번역된 양식은 원문을 화면에 띄울 때 바꿔 보여 주는 것이 아니라 별도로 승인된 객체이다. 초안 작성에 기계 번역을 쓸 수는 있지만, 참여자에게 가는 것은 IRB가 승인한 판이다. 실제로 제시된 언어를 기록해야 하는데, 승인된 번역이 없으면 참여자가 선호하는 언어와 다를 수 있다. 그 차이 자체도 보고할 가치가 있다. 연구가 누구를 배제하고 있는지를 IRB에 알려 주기 때문이다.
BIO-018의 ComprehensionAssessment는 방법(teach-back, quiz, questionnaire, interview), 점수, 전체 문항 중 정답 수, 평가자, 날짜를 담는다. 전자동의 시스템은 여기에 문항별 결과도 보관해야 한다. 어떤 문항을 틀렸는지, 무엇을 다시 설명했는지, 재설명 뒤의 점수가 얼마인지이다. 명세 부록 A.2의 사례(10문항 중 8문항 정답으로 통과했지만 5번과 9번은 재설명)는 이 문항들이 기록되어 있어야 의미가 있다. 참여자가 자기 말로 연구를 설명하는 되묻기(teach-back)의 경우, 평가자는 녹취록 대신 주제별로 구조화된 판단을 기록하는 편이 낫다. 자유 형식 녹취록은 아무도 감사하지 않을 개인정보일 뿐이다.
참조 SDK의 한 가지 성질 때문에 이 단계가 결정적이다. validateInformedConsent는 comprehensionScore가 빠지면 1.0을, participantCapacity가 빠지면 'full'을 기본값으로 쓴다. 이해도 평가가 없는 동의가 완벽하게 이해한 것처럼 채점된다는 뜻이다. 7.3절의 서비스는 이 경우 SDK 호출 자체를 거부하며, 여러분의 구현도 그래야 한다.
SignatureInfo.method에는 네 가지 값이 허용되며, 서로 바꿔 쓸 수 없다.
method | 의미 | 검증을 위해 저장할 것 | 주의점 |
|---|---|---|---|
handwritten | 종이에 한 자필 서명을 나중에 스캔한 것 | 스캔본, 입회인, 인쇄된 양식 버전과의 연결 | 종이 원본은 적용되는 보존 규칙에 따라 보관한다 |
electronic | 의사를 나타내는 모든 전자적 표시: 이름 입력, 클릭 서명, 태블릿 필기 | 인증된 신원, 시각, 서명의 의미("동의", "입회"), 화면에 표시된 문서의 해시 | 미국 FDA 규정이 적용되면 21 CFR Part 11이 전자서명과 전자기록 요건을 정한다 |
digital | 인증서에 기반한 암호학적 서명 | 서명값, 인증서 체인, 서명 시점의 검증 결과 | 인증서가 만료된 뒤에도 검증할 수 있어야 하므로 검증 증거를 보관한다 |
verbal | 구두 동의(주로 전화 또는 문해력이 낮은 참여자) | 취득자, 입회인, 사용한 설명 원고, 이를 허용한 IRB 결정 | IRB가 서면 기록을 면제했거나 입회인이 있는 약식 양식 절차를 승인한 경우에만 유효하다(45 CFR 46.117) |
SignatureInfo의 verified 플래그는 서명하는 사람이 아니라 확인을 마친 시스템이 설정해야 한다. 전자서명이라면 세션 시작 시 신원 확인과 문서 해시에 대한 서명 결속이, 디지털 서명이라면 인증서 검증이 그 확인이다. 어느 경우든 어떤 확인을 거쳤는지 기록에 남겨야 한다.
일부 참여자가 쓸 수 없는 전자동의 화면은 정의(justice)의 문제를 기술 결함으로 바꿔 놓는다. W3C 접근성 지침인 WCAG 2.2에 맞춰 화면 낭독기 지원, 글자 크기 조절, 충분한 명암 대비, 키보드 조작을 갖춰야 한다. 문해력이 낮은 참여자에게는 긴 스크롤 문서보다 쉬운 말 요약, 승인된 문구의 음성 낭독, 짧은 단락마다 이해도 문항을 하나씩 두는 방식이 효과적이다. SDK에 있는 교육적 취약 집단 보호 조치(쉬운 자료, 시각 보조, 되묻기, 입회인)는 IRB가 연구별로 켤 수 있는 설정이어야 하며, 그래야 추가 절차가 실제로 이루어졌다는 사실이 기록된다.
§8.1은 감사 추적을 "윤리적 결정의 완전한 기록"이라고 설명한다. 이 표현을 점검자가 믿을 수 있는 것으로 바꾸려면 두 가지 성질이 필요하다. 어떤 기록도 들키지 않고 바꾸거나 지울 수 없어야 하고, 각 기록에 그 결정이 왜 내려졌는지 복원할 수 있을 만큼의 맥락이 담겨 있어야 한다.
감사 로그는 통제할 수 있는 모든 계층에서 추가 전용이어야 한다. 애플리케이션에는 수정·삭제 경로가 없고, 애플리케이션이 쓰는 데이터베이스 역할에는 감사 테이블에 대한 수정·삭제 권한이 없으며, 백업도 같은 규칙으로 보존한다. 그다음 항목들을 사슬로 잇는다. 각 항목은 직전 항목의 해시(prevHash)와 자기 해시(hash)를 저장하는데, 자기 해시는 prevHash를 포함한 내용을 정규 직렬화한 값에 대해 계산한다. 과거 항목 하나를 바꾸면 그 해시가 바뀌고 그 뒤의 모든 연결이 끊긴다. 해시 함수로는 SHA-256이 적합하다. 정규 형식이 중요하다. 두 직렬화기가 키 순서를 다르게 내면 정직한 기록도 검증에 실패한다. RFC 8785(JSON 정규화 방식)가 하나의 정규 형식을 정의한다. 아래 예제는 키를 정렬하는 방식을 쓰는데, 자체 생성하는 기록에는 이것으로 충분하다.
해시 체인은 중간이 바뀌지 않았음을 증명하지만, 데이터베이스 접근 권한이 있는 사람이 가장 최근 항목들을 지워 버리는 것까지 막지는 못한다. 이 틈은 현재 체인 머리를 시스템 밖에 주기적으로 기록해서 막는다. 별도의 한 번 쓰기 저장소, 신뢰할 수 있는 시점 확인 서비스(RFC 3161), 또는 IRB 회의록이 그 장소가 될 수 있다. 검증은 체인을 처음부터 따라가며 확인하고, 머리를 마지막 앵커와 비교한다.
{
"seq": 18442,
"at": "2025-12-26T10:36:12Z",
"actor": { "id": "RN-001", "role": "consent-assessor" },
"action": "consent.validated",
"entity": "InformedConsent",
"entityId": "CONSENT-2025-001",
"consentFormVersion": "3.1",
"sdkVersion": "1.0.0",
"inputHash": "sha256:9f2c...e41a",
"output": { "isValid": true, "complianceScore": 0.976, "violations": [] },
"override": null,
"prevHash": "sha256:51b0...77c3",
"hash": "sha256:c8d4...0b19"
}
각 필드는 점검자가 묻는 질문에 답한다. 누가: 행위자 ID와 그가 행동한 역할이다. 같은 간호사가 한 연구에서는 평가자이고 다른 연구에서는 연구자일 수 있기 때문이다. 언제: 클라이언트가 아니라 서버가 찍은 ISO 8601 UTC 시각이다. 무엇을: 행위를 나타내는 동사와 그 대상 개체이다. 어떤 규칙으로: 동의서 버전과 SDK 버전(getVersion())이다. SDK 버전이 중요한 까닭은 SDK의 기준값이 앞으로 바뀔 설계상의 선택이기 때문이다. 버전 1.0.0에서 0.976으로 채점된 동의가 이후 판에서는 다른 점수를 받을 수 있으며, 기록은 어떤 규칙이 어떤 숫자를 낳았는지 보여 주어야 한다. 무엇을 입력으로: 입력 자체가 아니라 입력의 해시이다. 그래야 개인정보가 지울 수 없는 로그로 퍼지지 않으면서도, 다른 곳에 저장된 입력이 바뀌지 않았음을 증명할 수 있다. 어떤 결과로: 출력과, 사람이 재정의했다면 그 작성자와 사유이다.
예시의 0.976은 제4장에서 제시한 §8.3.1 기록의 정규형, 즉 데이터·검체의 향후 이용을 포함한 10개 항목이 모두 고지된 것으로 기록된 형태에 대해 참조 SDK가 돌려주는 값이다. 항목 완결 0.30, 이해도 0.30 × 0.92, 완전한 의사결정 능력 0.20, 서명 0.15, 서명한 입회인 0.05를 더한 것이다. 명세의 JSON은 이를 0.98로 반올림해 적었다. 전체 숫자를 저장하고 반올림은 표시할 때만 한다.
다음 서비스는 참조 SDK 둘레에 감사 추적과 두 가지 안전장치를 두른다. 먼저 대상 집단 이름을 정규화한다. 명세(§8.2.2)와 CLI는 'adults'라고 쓰는데 SDK는 'general-adults'만 인식하기 때문이다. 그 밖의 값은 취약 집단으로 취급되고, getEnhancedProtections가 그 값에 대해 undefined를 돌려주어 호출이 TypeError로 실패한다. 또 이 서비스는 이해도 평가가 없는 동의의 검증을 거부하고, 사람의 재정의를 정식 이벤트로 기록한다.
// ethics-service.ts - BIO-018 참조 SDK 래퍼 (npm 패키지가 아니라 로컬 소스를 가져온다)
import { createHash } from 'node:crypto';
import {
BioEthicsSDK,
EthicalRiskAssessment,
EthicalRiskResult,
InformedConsent,
ConsentValidationResult,
VulnerablePopulation,
} from '../bio-ethics/api/typescript/src';
const VULNERABLE: ReadonlySet<string> = new Set<VulnerablePopulation>([
'children', 'pregnant-women', 'prisoners', 'cognitively-impaired',
'economically-disadvantaged', 'educationally-disadvantaged',
'terminally-ill', 'ethnic-minorities', 'refugees',
]);
// 명세(8.2.2)와 CLI는 'adults', SDK는 'general-adults'만 인식한다.
// 그 밖의 값은 getEnhancedProtections()가 undefined를 돌려 TypeError로 끝난다.
export function normalizePopulation(p: string): VulnerablePopulation | 'general-adults' {
if (p === 'adults' || p === 'general-adults') return 'general-adults';
if (VULNERABLE.has(p)) return p as VulnerablePopulation;
throw new Error(`Unknown target population "${p}" - 추정하지 않고 거부`);
}
export interface AuditEntry {
seq: number; at: string;
actor: { id: string; role: string };
action: string; entity: string; entityId: string;
consentFormVersion?: string; sdkVersion: string;
inputHash: string; output: unknown;
override: { by: string; decision: string; reason: string } | null;
prevHash: string; hash: string;
}
export interface AuditStore {
last(): Promise<AuditEntry | undefined>;
append(e: AuditEntry): Promise<void>; // 중복 seq는 반드시 거부
}
// 안정 직렬화: 키를 정렬해 같은 내용이면 항상 같은 해시가 나오게 한다.
function canonical(v: unknown): string {
if (v instanceof Date) return JSON.stringify(v.toISOString());
if (v === null || typeof v !== 'object') return JSON.stringify(v);
if (Array.isArray(v)) return `[${v.map(canonical).join(',')}]`;
const o = v as Record<string, unknown>;
return `{${Object.keys(o).sort()
.filter((k) => o[k] !== undefined)
.map((k) => `${JSON.stringify(k)}:${canonical(o[k])}`).join(',')}}`;
}
const sha256 = (s: string) => 'sha256:' + createHash('sha256').update(s).digest('hex');
export class EthicsService {
private sdk = new BioEthicsSDK();
constructor(private store: AuditStore, private actor: { id: string; role: string }) {}
private async record(
action: string, entity: string, entityId: string,
input: unknown, output: unknown, consentFormVersion?: string,
override: AuditEntry['override'] = null,
): Promise<void> {
const prev = await this.store.last();
const body = {
seq: (prev?.seq ?? 0) + 1,
at: new Date().toISOString(),
actor: this.actor, action, entity, entityId, consentFormVersion,
sdkVersion: this.sdk.getVersion(),
inputHash: sha256(canonical(input)),
output, override,
prevHash: prev?.hash ?? 'sha256:genesis',
};
await this.store.append({ ...body, hash: sha256(canonical(body)) });
}
async assessRisk(
input: Omit<EthicalRiskAssessment, 'targetPopulation'> & { targetPopulation: string },
): Promise<EthicalRiskResult> {
const assessment: EthicalRiskAssessment = {
...input, targetPopulation: normalizePopulation(input.targetPopulation),
};
const result = this.sdk.assessEthicalRisk(assessment);
await this.record('risk.assessed', 'EthicalRiskAssessment', input.studyType, assessment, result);
return result;
}
async validateConsent(c: InformedConsent): Promise<ConsentValidationResult> {
// SDK는 comprehensionScore 기본값 1.0, capacity 기본값 'full'을 쓴다. 기본값에 맡기지 않는다.
if (!c.comprehension) throw new Error(`${c.consentId}: 이해도 평가 기록 없음`);
const input = {
participantId: c.participantId,
studyId: c.studyId,
consentForm: c.elements,
participantCapacity: c.participantCapacity,
comprehensionScore: c.comprehension.score,
witnessPresent: c.witnessPresent,
signature: {
participant: c.signatures.participant.signed,
witness: c.signatures.witness?.signed ?? false,
lar: c.signatures.legallyAuthorizedRepresentative?.signed ?? false,
date: c.signatures.participant.date,
},
};
const result = this.sdk.validateInformedConsent(input);
await this.record('consent.validated', 'InformedConsent', c.consentId, input, result, c.version);
return result;
}
// 점수와 다른 사람의 결정은 조용히 적용하지 않고 기록으로 남긴다.
async recordOverride(entity: string, entityId: string, decision: string, reason: string) {
if (reason.trim().length === 0) throw new Error('재정의에는 서면 사유가 필요하다');
await this.record('decision.overridden', entity, entityId, { decision }, null, undefined,
{ by: this.actor.id, decision, reason });
}
}
설계에 관해 몇 가지를 덧붙인다. normalizePopulation은 알 수 없는 값을 성인으로 간주하지 않고 거부한다. 인식하지 못한 집단을 조용히 비취약 집단으로 처리하는 것이야말로 보호 규칙이 막으려는 실패이기 때문이다. AuditStore.append는 중복된 seq를 거부해야 한다(고유 제약 하나면 충분하다). 그래야 동시에 쓰는 두 작성자가 같은 머리에서 체인을 이어 붙이지 못하고, 진 쪽이 다시 시도한다. 재정의 메서드는 서면 사유를 요구한다. 제8장의 8.5절은 점수가 판단 보조 도구일 뿐이라고 논증하는데, 점수와 다른 사람의 결정이 드러나고 검토될 수 있는 곳이 바로 감사 추적이다.
제4장의 정규형 §8.3.1 기록으로 이 서비스를 돌리면 isValid: true, 점수 0.976이 나온다(명세에 인쇄된 그대로의 기록은 향후 이용 고지가 없어 제5장에서 보았듯이 E001로 실패한다). 성인, 약물 중재, 최소 위험을 약간 초과, 이익 3개, 위험 2개로 assessRisk를 돌리면 SDK는 위험 점수 (0.4 + 0.6) / 2 + 2 × 0.05 = 0.6, 이익 점수 0.6, 비 1.0, 윤리 점수 0.5를 계산한다. 이는 "승인하되 모니터링 강화" 구간의 경계에 정확히 걸리는데, IEEE-754 부동소수점에서는 결과가 1.0000000000000002로 나와 통과한다. 위험을 하나만 더 적어도 결과는 "revise"로 바뀐다. 감사 항목이 원시 출력값을 저장하는 이유이자, 제8장이 경계값을 명시적으로 시험하는 이유이다.
모든 동의 이벤트는 양식 버전을, 모든 양식 버전은 그것을 승인한 IRB 결정을 가리켜야 한다. 두 연결이 갖춰지면 세 가지 질문이 간단한 조회가 된다. 나중에 대체된 버전에 서명한 참여자는 누구인가, 승인일 이전에 어떤 버전에 서명한 사람이 있는가, 변경 승인 뒤 재동의가 필요한 참여자는 누구인가. 철회도 삭제가 아니라 이벤트이다. 동의 기록은 남고, 철회 항목이 언제, 어떻게, 데이터와 검체의 어떤 향후 이용에서 참여자가 빠졌는지를 기록한다.
BIO-018 §6.1은 기본선을 정한다. AES-256 암호화, 감사 로그를 갖춘 역할 기반 접근 통제, 외부 백업을 둔 보안 저장, 암호화된 전송, 비식별화를 위한 HIPAA 18개 식별자 제거이다. 또 네 가지 보호 수준을 정의하는데, GeneticData.protectionLevel은 이를 anonymous, de-identified, confidential, public으로 담는다. 아래 표는 수준별 통제를 정리한 것이다.
| 수준(§6.1) | 의미 | 공학적 통제(이 책의 권고) |
|---|---|---|
1 · anonymous | 식별자가 없고 재식별할 수 없음 | 유전체·엑솜 데이터로는 거의 달성할 수 없다. 서열 데이터에 이 수준이 붙어 있으면 표시로 믿지 말고 검토 대상으로 삼는다 |
2 · de-identified | 코드화되어 키로 재식별 가능 | 키는 별도 관리자가 보관하고, 연구 시스템은 코드만 본다. 키 조회는 목적을 밝혀야 하는 감사 대상 이벤트이다 |
3 · confidential | 식별되지만 보호됨 | 저장·전송 시 암호화, 최소 권한 RBAC, 기록 단위 접근 로그, 결과 반환 시 임상 수준의 취급 |
4 · public | 공개 공유 | 집계 데이터나 명시적으로 동의한 데이터만. 공개는 dataSharingConsent와 연결된 감사 이벤트이다 |
저장 데이터는 GCM 같은 인증 암호 모드의 AES-256으로 암호화하고, 키는 애플리케이션 설정 파일이 아니라 키 관리 서비스나 하드웨어 보안 모듈에 둔다. 전송 구간은 TLS 1.2 이상으로 암호화한다(TLS 1.3은 RFC 8446에 규정되어 있다). 역할 기반 접근 통제는 데이터 모델에 이미 있는 연구 역할(연구책임자, 코디네이터, 평가자, 모니터, IRB 심의위원)을 따르되 연구 단위로 범위를 한정해서, 한 연구의 유전체에 접근할 수 있다고 다른 연구의 유전체까지 볼 수 있게 되지 않도록 한다. 수준 2와 3의 유전체 데이터는 쓰기뿐 아니라 모든 읽기를 감사 이벤트로 기록한다. 유전체 데이터에서 개인정보 침해가 일어나는 곳은 읽기이다.
대부분의 연구 데이터는 수준 2에 있고, 그 안전성은 전적으로 누가 키를 쥐고 있는가에 달려 있다. 흔히 쓰는 방식은 정직한 중개자(honest broker)이다. 연구팀 밖의 사람이나 서비스가 코드와 신원의 대응표를 보관하고, 조치 가능한 우연적 발견을 돌려주는 경우처럼 문서화되고 승인된 목적이 있을 때에만 대응 관계를 내준다. 연구 데이터베이스에는 신원을 곧바로 조회할 수 있는 필드가 하나도 없어야 한다. GDPR에서 가명 처리된 데이터는 여전히 개인정보이므로(전문 제26항), 연구팀이 아무도 식별할 수 없더라도 수준 2 데이터는 개인정보 보호법의 적용을 받는다.
HIPAA의 세이프 하버 방식(45 CFR 164.514(b)(2))이 열거한 18개 식별자를 지우면 이름, 날짜, 주소, 기록 번호가 사라진다. 그러나 유전체 자체는 바뀌지 않는다. 유전체는 개인마다 고유하고 친족과 일부를 공유한다. 발표된 연구들은 Y 염색체 표지를 족보 데이터베이스와 대조해 성씨를 추론할 수 있음을 보였고(Gymrek 외, Science, 2013), 요약 통계만으로도 특정인이 혼합 데이터셋에 포함되어 있는지 알아낼 수 있음을 보였다(Homer 외, PLoS Genetics, 2008). BIO-018 시스템에 주는 실무적 결론은 서열 데이터로는 수준 1에 거의 도달할 수 없고, 공유는 공개 배포가 아니라 데이터 이용 계약을 동반한 통제 접근을 거쳐야 한다는 것이다.
유전체 데이터의 모든 외부 반출을 감사 기록이 남는 결정으로 다룬다. 반출 전에 다음을 확인한다. 참여자의 dataSharingConsent와 secondaryUseConsent가 수령자와 목적을 포괄하는가, 데이터셋에 목적에 필요한 필드만 들어 있는가, 희귀 변이·소규모 하위 집단·연결된 표현형 데이터의 재식별 위험을 검토했는가, 수령자가 재식별 시도를 금지하는 계약에 묶여 있는가. GDPR이 적용되면 유전 데이터를 대규모로 처리할 때 통상 데이터 보호 영향평가(제35조)가 요구되며, 설계 단계부터의 데이터 보호(제25조)가 바로 이 절에서 설명한 아키텍처이다.
§9.4는 주요 규정으로 45 CFR 46, 21 CFR 50·56, ICH-GCP, GDPR, 각국 규정을 들고, §10.2는 HIPAA, GINA, EU 임상시험규정을 더한다. 그러나 명세는 BIO-018 시스템의 어느 부분이 어느 규칙을 충족하는지 말하지 않는다. 아래 표는 이 책이 정리한 대응이다. 준수 매트릭스의 출발점일 뿐 법률 자문이 아니다. 요건은 연구 유형, 의뢰자, 관할에 따라 달라지고 규정은 개정된다.
| 규정 | 요건(요약) | 이를 뒷받침하는 BIO-018 기록 또는 구성요소 |
|---|---|---|
| 45 CFR 46(개정 공통규칙, 미국) §46.116 | 사전 동의의 일반 요건과 구성 요소, 간결한 핵심 정보 부분 포함 | ConsentFormElements, 버전 관리 양식(7.2) |
| 45 CFR 46.117 | 동의의 문서화, 입회인을 둔 약식 양식 절차, IRB의 문서화 면제 | signatures, SignatureInfo.method, witnessPresent |
| 45 CFR 46.111 | IRB 승인 기준(위험 최소화와 합리성, 공평한 대상자 선정, 동의, 개인정보) | IRBSubmission, RiskBenefitAnalysis, 개인정보 보호 구성요소 |
| 45 CFR 46.115 | IRB 기록. 연구 종료 후 최소 3년 보존 | 감사 추적, 관할별 보존 정책 |
| 45 CFR 46 Subpart B·C·D | 추가 보호: 임신부와 태아, 수감자, 아동 | vulnerablePopulations, EnhancedProtection, ChildAssent |
| 21 CFR Part 50·56(FDA) | FDA 규제 대상 임상시험의 사전 동의와 IRB 요건 | 동의·IRB 구성요소 |
| 21 CFR Part 11(FDA) | 전자기록과 전자서명: 안전하고 컴퓨터가 생성하며 시각이 찍힌 감사 추적, 서명의 표시(이름, 일시, 의미) | 감사 추적(7.3), 의미와 검증 정보를 담은 SignatureInfo |
| 21 CFR 312.32(FDA IND 안전성 보고) | 중대하고 예상하지 못한 의심 이상약물반응은 15일(역일) 이내, 그중 사망 또는 생명을 위협하는 경우는 7일 이내 보고 | AdverseEvent, 보고 구성요소의 보고 기한 |
| ICH E6(R3) 임상시험 관리기준(2025년 1월 채택) | 동의, 안전성 보고, 전산 시스템의 데이터 무결성과 감사 추적, 필수 문서 | 여섯 구성요소 전부 |
| GDPR(EU) 제9·25·32·35·89조 | 민감정보로서의 유전 데이터, 설계 단계부터의 데이터 보호, 보안, 영향평가, 연구 목적 처리의 보호조치 | GeneticData.protectionLevel, 개인정보 보호 구성요소, secondaryUseConsent |
| EU 임상시험규정 536/2014 | 사전 동의(제29조), 임상시험 마스터 파일 최소 25년 보관(제58조) | 동의 구성요소, 보존 정책 |
| HIPAA 프라이버시 규칙(미국) | 비식별화(세이프 하버 또는 전문가 판정), 연구 이용 승인 | 개인정보 보호 구성요소, 수준 2 취급 |
| GINA(미국) | 건강보험과 고용에서의 유전 차별만 금지. 생명보험, 장애보험, 장기요양보험은 적용 대상이 아님 | 공개 위험에 관한 동의서 문구, GeneticData 접근 통제 |
| 한국: 생명윤리 및 안전에 관한 법률 | 기관생명윤리위원회(IRB)의 설치와 등록, 인간대상연구와 인체유래물연구의 서면 동의, 인체유래물은행의 허가 | IRB 구성요소(기관 등록 정보), 동의 구성요소, 바이오뱅크 이용을 위한 GeneticData.secondaryUseConsent |
이 표에서 구현상의 결론 두 가지가 나온다. 첫째, 보존 기간은 하나의 숫자가 아니다. 명세의 "최소 7년"(§3.2.2)은 보편 규칙이 아니다. 미국 IRB 기록은 45 CFR 46.115에 따라 연구 종료 후 최소 3년, EU 임상시험 마스터 파일은 최소 25년 보관해야 한다. 시스템은 기록마다 보존 등급을 저장하고, 적용되는 규칙 가운데 가장 긴 것을 기준으로 종료일을 계산해야 한다. 둘째, 보고 기한 역시 명세 §4.5의 24시간·7일·15일·30일 표가 아니다. 그 표는 기관 내부 정책의 예시로는 쓸 수 있지만, 보고 서비스는 해당 관할의 규정상 기한과 기관마다 다른 IRB 자체 보고 정책을 적용해야 한다.
한국 항목은 대부분의 나라에서 되풀이되는 유형을 보여 준다. 등록된 기관위원회와 인체유래물 이용에 대한 동의를 요구하는 국가 법률이 있고, 거기에 고유한 서식과 보고 의무가 따른다. 관할별 요건은 코드 곳곳에 흩어 두지 말고 기관별 설정으로 관리한다. 조문 번호와 현행 문구는 의존하기 전에 공식 법령 원문으로 확인해야 한다.
BIO-018 시스템이 홀로 서는 경우는 드물다. 연구기관은 이미 연구·기관 운영을 위한 임상시험 관리 시스템(CTMS), 증례기록서를 위한 전자 자료 수집(EDC) 시스템, 유전 검사를 위한 검사실 시스템, 그리고 흔히 바이오뱅크 재고 관리 시스템을 운영한다. 명세(§10.3)와 README는 관련 WIA 표준의 이름만 들 뿐 인터페이스는 정의하지 않는다. 따라서 이 절의 내용은 모두 이 책의 권고이다.
GeneticData와 IncidentalFinding 기록의 자연스러운 출처이다. 연동 지점은 결과 반환 결정이다. 검사실이 변이와 그 임상적 의의를 보고하면, BIO-018 시스템은 참여자의 returnOfResults 선호와 §6.3의 반환 기준에 따라 임상적 확인과 유전상담을 거쳐 그 발견을 돌려줄지 결정한다.GeneEditingEvaluation의 기술적 입력, 특히 SDK가 평균을 내는 표적 이탈, 면역 반응, 모자이시즘 위험값의 출처이다. 각 값이 어디서 왔는지 기록한다. 출처 없는 위험 숫자는 증거가 아니다.가장 가치 있는 연동은 가장 단순한 것이기도 하다. 유효한 동의 없이는 등록도, 자료 입력도 없다. 동의 서비스는 승인된 현행 양식 버전 기준으로 동의가 검증을 통과하면 이벤트를 발행하고, 참여자가 철회하거나 재동의가 필요해지면 또 다른 이벤트를 발행한다. CTMS는 등록 상태를 갱신하고, EDC는 해당 참여자의 증례기록서를 열거나 잠근다. 반대 방향으로 짜인 연동, 즉 EDC가 등록을 기록하고 동의 시스템은 나중에 그 사실을 알게 되는 구조는 동의 관리에서 가장 흔한 점검 지적 사항을 낳는다. 동의가 문서화되기 전에 자료가 수집되는 것이다.
안전성 데이터에는 단일한 진본이 필요하다. 이상사례는 보통 연구자가 평가하는 EDC에 기록된다. BIO-018 보고 구성요소는 그 사례를 받아 윤리 측면의 의무(IRB 보고, 보고 기한, 프로토콜 이탈과의 연결)를 맡아야 하며, 연구자가 또 한 번 입력해야 하고 점점 어긋나는 두 번째 사본을 따로 유지해서는 안 된다.
BIO-018은 자체 JSON과 TypeScript 타입을 정의하지만 교환 형식은 정의하지 않는다. 전자의무기록이나 최근의 연구 플랫폼과 연동하려면 HL7 FHIR 리소스가 합리적인 목표이다. 아래 대응은 명세의 일부가 아니라 이 책의 권고이다. FHIR R4와 R5 사이에는 요소 이름이 다르므로(특히 Consent 리소스가 크게 바뀌었다) 상대 시스템이 지원하는 버전으로 확인해야 한다.
| BIO-018 기록 | FHIR 리소스 | 비고 |
|---|---|---|
InformedConsent | Consent(서명된 양식은 DocumentReference) | 양식 버전과 언어는 문서와 함께 전달한다. 이해도와 의사결정 능력에는 표준 요소가 없어 확장이 필요하다 |
IRBProtocol / IRBSubmission | ResearchStudy | 연구 상태는 일부만 대응된다. IRB 결정과 만료일은 확장이나 연결 문서로 전달하는 편이 낫다 |
| 등록 | ResearchSubject | 연구, 환자, 동의를 참조한다 |
AdverseEvent | AdverseEvent | 중증도, 중대성, 결과, 의심 원인의 인과관계에 대응 요소가 있으나 값 집합이 SDK의 5단계 척도와 다르다 |
| 감사 항목 | AuditEvent, Provenance | 내보내기 전용. 해시 체인은 BIO-018 저장소에 둔다 |
형식이 무엇이든 SDK의 값 집합은 명시적으로 변환하고, 서로 맞지 않는 곳을 문서화한다. Causality는 다섯 단계(unrelated, unlikely, possible, probable, definite)인데 상대 시스템은 대개 더 적은 단계를 쓴다. "possible"을 "관련 있음"과 "관련 없음" 중 어디로 접을지는 그 자체로 안전성에 관한 결정이므로 기록해야 한다.
어떤 배치든 준수하려면 여섯 구성요소가 모두 필요하다. README는 인간대상연구, 유전 검사, 줄기세포 연구, 유전자 치료, 바이오뱅크 관리, 합성생물학을 활용 사례로 든다. 그중 네 가지를 보면 같은 구성요소에 걸리는 부하가 얼마나 다른지 알 수 있다. 아래 표는 배치 유형별로 가장 무거운 요건이 놓이는 곳을 표시한다.
| 배치 유형 | 가장 무거운 구성요소 | 특별한 설정이 필요한 부분 |
|---|---|---|
| 임상시험(의약품·의료기기) | 동의 관리, 보고, 감사 추적 | 변경 승인 후 재동의, 규정상 안전성 보고 기한, CTMS·EDC 연동, 전자기록에 대한 Part 11과 ICH E6(R3)의 기대 수준 |
| 바이오뱅크 | 동의 관리, 개인정보 보호 | 향후 이용을 위한 포괄 동의 또는 단계별 동의, 보관 검체와 파생 데이터까지 닿는 철회, 분양할 때마다의 반출 검토, 장기 보존 |
| 유전 검사실 | 개인정보 보호, 보고 | 참여자별 결과 반환 정책, 임상적 확인과 상담을 포함한 우연적 발견 처리 흐름, 가족에 대한 함의 처리 |
| 유전자 치료 프로그램 | 위험 평가, IRB 제출, 보고 | 유전자 편집 결정 기록, IRB와 병행하는 기관생물안전위원회, 장기 추적. SDK는 5년을 추가하지만 규제기관은 더 긴 기간을 기대할 수 있다. 미국 FDA 지침은 일부 유전자 편집 제품과 통합형 벡터 제품에 최대 15년 추적을 권고한다 |
임상시험의 핵심 경로는 승인된 양식 버전 → 유효한 동의 → 등록 이벤트 → 자료 입력으로 이어지는 사슬이며, 그 순서를 증명하는 것이 감사 추적이다. 바이오뱅크에서는 몇 년 전에 받은 동의가 새로운 요청 하나하나를 여전히 규율해야 하므로, 반출할 때마다 동의 기록의 범위와 secondaryUseConsent를 확인하고, 동의가 포괄하지 않는 새 이용은 재연락이나 IRB 심의로 넘긴다(§6.4). 유전 검사실은 개인정보 보호와 제3장의 결과 반환 매트릭스가 지배한다. 유전자 치료 프로그램은 SDK에서 가장 복잡한 위험 판단 논리를 돌리며, 그 결정에는 가장 긴 모니터링 의무가 뒤따른다.
BIO-018 구현은 공통 규율 하나를 공유하는 여섯 개의 서비스이다. 윤리적으로 의미 있는 결정은 모두 추가 전용이고 해시로 연결된 기록을 남기며, 그 기록은 누가, 어느 양식 버전과 어느 규칙 버전 아래에서, 어떤 입력으로, 어떤 결과를 냈는지를 사람의 재정의까지 포함해 말해 준다. 전자동의에는 언어별로 승인된 버전 관리 양식, 문항 단위의 이해도 기록, 유형에 맞는 증거를 갖춘 서명 방식이 필요하다. 유전체 데이터에는 수준 2 데이터의 키 보관 체계와 모든 반출 전 검토가 필요하다. 서열 데이터는 익명화에 저항하기 때문이다. 규정 대응표는 보존 기간과 보고 기한을 명세의 고정 표가 아니라 적용 관할에서 가져와야 함을 보여 준다. 참조 SDK는 감싸서 쓰면 채점의 핵심으로 쓸 수 있다. 'adults'를 정규화하고, 이해도 데이터가 없으면 거부하고, 재정의를 기록하면 된다.
제8장은 이 구성요소들을 시험할 수 있는 대상으로 바꾼다. 적합성 시험 벡터, 이 장과 제5장에서 짚은 SDK 결함에 대한 회귀 시험, 그리고 시스템 전체를 점검하는 감사를 다룬다.