제7장

제7장: 배치 운영 프로토콜과 시스템 통합

WIA-BIO-015 배치가 어떤 상태를 거쳐 가는지, 측정값이 어떻게 알람과 판단으로 바뀌는지, 그리고 표준의 객체가 실제 공장의 DCS·히스토리안·MES·LIMS 사이 어디에 놓이는지를 다룬다.

앞 장들은 WIA-BIO-015를 공식과 데이터 타입의 묶음으로 읽었다. 그러나 제조 배치는 공식이 아니다. 배치는 2주 이상에 걸쳐 전개되는 사건의 연쇄이고, 여러 컴퓨터 시스템과 많은 사람이 관여하며, 끝나고 나면 품질 부서가 검토하고 서명할 수 있는 기록을 남겨야 한다. 이 장은 표준을 하나의 운영 프로토콜로 읽는다. 배치가 머무를 수 있는 상태는 무엇인지, 어떤 근거가 배치를 다음 상태로 넘기는지, 센서 값이 프로브에서 운전자 화면을 거쳐 전자 배치 기록에 이르기까지 어떤 경로를 밟는지, 그리고 그 경로 가운데 표준이 규정하는 부분, 참조 SDK가 구현한 부분, 통합 담당자에게 남겨진 부분이 각각 어디인지를 구분한다.

이 장 전체에서 세 가지 출처를 분리해 다룬다. 명세서(WIA-BIO-015-v1.0.md, 특히 §3.2, §6, §8.1, §9)는 규범이다. TypeScript 타입과 SDK(types.ts, index.ts)는 사실상의 전송 형식이자 참조 동작이다. 그 밖의 모든 내용은 공학적 권고이거나 예시이며, 사례 시나리오에 나오는 수치를 포함해 모두 그렇게 표시한다.

7.1 프로토콜로서의 배치 수명주기

7.1.1 상태 변수는 하나가 아니라 셋이다

WIA-BIO-015에는 서로 독립적인 상태 변수가 세 개 있고, 이 셋은 혼동하기 쉽다. BioreactorStatus.phase는 생물학적 상태, 즉 배양이 성장 곡선의 어디쯤에 있는지를 나타낸다(inoculation, lag, exponential, stationary, death, harvest). BioreactorStatus.status는 설비의 상태로, 용기가 running, paused, error, complete 중 어디에 있는지를 뜻한다. BatchSummary.status는 공장 안을 이동하는 물질 단위로서의 로트 상태이며 running, harvested, purifying, complete, failed 값을 갖고, 이와 별도로 qualityStatus가 pending, pass, fail 값을 갖는다.

이 셋을 분리하는 것은 실무에서 중요하다. 예컨대 프로브 교체를 위한 관리된 정지 동안 반응기는 paused이지만 배양 자체는 생물학적으로 여전히 exponential일 수 있다. 또 출하 시험 결과가 아직 보고되지 않았다면, 배치는 제조 관점에서 complete이면서도 qualityStatus는 pending일 수 있다. 이 축들을 하나의 "상태" 필드로 합쳐 버린 구현은 조만간 사실이 아닌 내용을 기록하게 된다.

7.1.2 배양 단계 상태 기계

명세서 §3.2.1은 회분식 배양의 성장 단계를 대략적인 시간 창과 함께 제시한다. 지연기 0–12시간, 대수기 12–72시간, 정지기 72–120시간, 사멸기 120시간 이후다. 이 시간 창은 일반론이다. CHO 유가식 배양은 공급(feeding)이 정지기와 사멸기를 늦추기 때문에 훨씬 오래 생산 상태를 유지하는 것이 보통이며, 같은 절이 수확 기준으로 "10–14일차(포유류)"를 따로 적어 둔 이유도 여기에 있다. 따라서 이 시간 창은 단순 회분식 배양의 기본값으로 읽어야 하며, 전이 규칙으로 쓰면 안 된다.

표준은 배양이 어느 단계에 있는지를 구현체가 어떻게 판정하는지 정하지 않으며, SDK도 phase를 계산하지 않고 전달만 한다. 아래 도식은 명세서와 모순되지 않으면서 데이터 모델이 이미 담고 있는 양만으로 구성한 전이 체계다. 화살표 위의 조건은 이 책의 권고이며 규범 문구가 아니다.

                 접종물 이송, 첫 시료 채취
  [inoculation] ─────────────────────────────────────────▶ [lag]
                                                             │
                 최근 구간의 μ가 상승해 기대 최댓값          │
                 부근에서 유지됨                             ▼
                                                        [exponential]
                                                             │
                 μ가 0에 가까워지고 VCD가 평탄해짐           │
                 (공급으로 며칠간 이 단계에 머물 수 있음)    ▼
                                                        [stationary]
                                                             │
                 VCD 감소, 생존율이 꾸준히 하락              │
                                                             ▼
                                                          [death]
                                                             │
   모든 단계 ── 수확 기준 충족(§3.2.1): ────────────────────┤
                생존율 < 70 %, 역가 최대 도달,               ▼
                또는 계획된 10–14일차 도래                [harvest]

이 도식에서 두 가지를 읽을 수 있다. 첫째, harvest는 어느 단계에서든 도달할 수 있다. 3일차의 오염(B005)도 14일차의 계획 수확과 마찬가지로 배양을 끝내며, 다만 이 경우 BatchSummary.status는 failed로 넘어간다. 둘째, 단계는 잡음이 섞인 측정값으로부터 시간 구간에 걸쳐 도출한 추정치다. 따라서 시료 하나로 단계를 바꿀 것이 아니라 이력으로부터 다시 계산해야 하며, 어떤 규칙과 어떤 구간으로 판정했는지 함께 저장해 두어야 나중에 검토자가 같은 판정을 재현할 수 있다.

단계권장 진입 근거권장 이탈 근거주요 관찰 항목
inoculation종배양 이송 완료, 이송 후 첫 시료 기록초기 VCD와 생존율이 배치 기록 기준과 대조·확인됨접종 밀도, 종배양 생존율
lag세포가 새 용기에 들어가 μ가 낮음구간 μ가 일관되게 상승이송 후 pH·DO 안정화
exponential세포주 기대값에 가까운 μ가 지속μ 감소, VCD가 평탄해지기 시작산소 요구량, 포도당 고갈, 젖산 생성
stationaryVCD가 대체로 일정VCD와 생존율이 떨어지기 시작역가 축적, 젖산·암모니아
death연속 시료에서 생존율 하락수확 기준 충족70 %를 향한 생존율 추세, 세포 파괴로 방출되는 숙주 물질의 품질 위험
harvest§3.2.1 기준 중 하나 충족 또는 종료 결정배양액이 정화 공정으로 이송됨정화까지의 경과 시간, 수확 부피

7.1.3 수확 기준은 임계값이 아니라 판단이다

명세서 §3.2.1은 수확 기준 세 가지를 "또는"으로 묶어 제시한다. 생존율 70 % 미만, 최대 역가 도달, 포유류 배양의 경우 10–14일차다. 70 %라는 값은 SDK의 BIO_CONSTANTS.MIN_VIABILITY이기도 하며, monitorBioreactor가 치명(critical) 알람과 함께 "Consider harvesting soon or investigating culture conditions"라는 권고를 내는 임계값이기도 하다. 통합 담당자는 이 일치가 의미하는 바를 알아차려야 한다. 같은 사건이 수확 신호이자 치명 알람인 것이다. 잘 설계된 운영 절차는 이를 미리 대비한다. 예를 들어 생존율 추세가 70 % 돌파를 예측하는 시점에 수확을 계획해 두면, 치명 알람은 뜻밖의 사건이 아니라 계획된 조치의 확인이 된다.

"최대 역가 도달"은 시료 하나로는 알 수 없다. 실무에서는 연속 역가 측정값이 분석 변동 이상으로 더 오르지 않는 평탄 구간으로 판단한다. SDK의 ParameterTrend 타입은 이를 표현하는 데 필요한 필드(trend, rateOfChange, predicted)를 정확히 갖추고 있지만, §7.2에서 보듯 참조 구현은 이 값을 데이터로부터 계산하지 않는다. 마지막으로 달력 기준은 마스터 배치 기록에 속한다. 계획된 배양 기간은 밸리데이션된 공정 변수이므로, 배양이 건강해 보이더라도 밸리데이션된 범위 밖에서 수확하면 일탈이 된다.

7.1.4 로트 상태 기계

BatchSummary.status는 한 방향으로만 움직인다. running → harvested → purifying → complete이며, failed는 모든 상태에서 도달할 수 있다. 이 타입은 각 단계에서 채워야 할 필드를 담고 있으므로, 구현체가 기록할 때마다 검사할 수 있는 간단한 불변 조건을 세울 수 있다.

전이계기설정해야 할 필드권장 불변 조건
(신규) → running생산 생물반응기 접종batchId, product, cellLine, startDatequalityStatus가 없거나 pending
running → harvested반응기 단계가 harvest가 됨harvestDate, finalTiter, totalProduct, productivityharvestDate가 startDate보다 뒤
harvested → purifying청징 수확액을 포획 단계에 적재사용한 정제 프로토콜과의 연결해당 배치의 PurificationProtocol이 존재
purifying → complete원료의약품 충전, QC 결과 보고qualityStatusqualityStatus는 pass 또는 fail이며 pending이 아님
모든 상태 → failed오염, 설비 고장, 로트 부적합일탈 시스템에 사유 기록failed에서 나가는 전이 없음

통합에서 자주 걸리는 단위 차이가 하나 있다. BatchSummary.productivity는 g/L/day로 문서화되어 있지만, 명세서의 부피 생산성 Qp(부록 A.2)는 g/L/h 단위다. SDK의 calculateProductivity는 두 값을 모두 돌려준다(시간당 value와 perDay). 요약 기록에는 항상 perDay를 넣어야 한다.

7.2 모니터링 루프

7.2.1 측정의 세 계층

명세서 §6.1은 속도, 침습성, 신호의 성격이 서로 다른 세 가지 측정군을 기술한다. 매초 읽는 pH 프로브와 30분마다 갱신되는 라만 예측값은 같은 종류의 근거가 아니므로, 모니터링 계층은 이들을 다르게 취급해야 한다.

계층명세서가 열거한 항목명세서상 성능 수치값의 성격
온라인 센서(§6.1.1)pH, 온도, 용존 산소, 압력, 교반pH ±0.05, 온도 ±0.1 °C, DO ±2 %, 압력 ±0.01 bar, 교반 ±5 rpm직접적인 물리 측정, 연속
앳라인 분석(§6.1.2)포도당, 젖산, 글루타민, 암모니아, 생존 세포 밀도결과까지 5–15분. 예: 포도당 0.1–25 g/L, 젖산 0.1–40 mM, VCD 105–107 cells/mL시료를 채취해 분석, 불연속
분광 분석(§6.1.3)라만: 포도당, 역가, 세포 밀도, 대사물. NIR: 총단백질, 세포, 배지 성분라만은 15–30분 간격, 비침습. 다변량 모델(PLS, PCR)로 보정스펙트럼에 대한 모델 예측값

마지막 행은 특히 강조할 필요가 있다. 라만 "포도당" 값은 포도당 측정값이 아니다. 스펙트럼에 부분최소제곱(PLS) 또는 주성분 회귀(PCR) 모델을 적용한 출력이다. 그 타당성은 보정 데이터 세트가 현재 배치의 조건을 포괄했느냐에 달려 있다. 따라서 구현체는 예측값마다 모델 식별자와 버전을 함께 기록하고, 앳라인 기준 분석법과 주기적으로 대조해야 한다. 두 값이 모델의 밸리데이션된 오차를 넘어 벌어지면 예측값을 조용히 믿을 것이 아니라 등급을 낮춰야 한다.

7.2.2 SensorReading에서 BioreactorStatus로

데이터 모델은 개별 값을 위해 SensorReading을 제공하며, 여기에는 quality 플래그(good, uncertain, bad)와 calibrated 불리언이 있다. 그러나 모니터는 판독값을 직접 받지 않는다. monitorBioreactor의 입력은 conditions와 metrics가 각각 단일 숫자로 채워진 BioreactorStatus 스냅숏 전체다. 판독값 흐름을 이 스냅숏으로 바꾸는 누군가가 있어야 하며, 표준은 이 집계 단계를 구현자에게 맡긴다. 다음 세 규칙이 이 단계를 정직하게 유지해 준다.

7.2.3 monitorBioreactor가 하는 일과 하지 않는 일

참조 모니터는 생존율, pH, 온도, 용존 산소, 그리고 값이 있으면 젖산과 암모니아를 검사하며, 항목마다 치명 구간과 그보다 좁은 경고 구간 두 가지를 적용한다. 전체 임계값 표는 제6장에서 제시했다. 프로토콜 관점에서는 개별 수치보다 이 함수의 세 가지 성질이 더 중요하다.

  1. 알람 객체나 코드가 아니라 문자열을 반환한다. 치명 소견은 criticalAlarms에, 나머지는 warnings에, 권고 조치는 recommendations에 문자열로 담긴다. 이 함수는 BioreactorStatus.alarms를 채우지 않고, BioreactorAlarm 레코드를 만들지 않으며, 명세서의 오류 표(§9.3)가 낮은 생존율·높은 젖산·낮은 역가·pH 이탈·오염·설비 고장에 대응시킨 BioErrorCode B001–B006도 붙이지 않는다. 소견을 코드와 알람 레코드로 옮기는 일은 통합 담당자의 몫이다.
  2. 추세 값은 자리표시자다. 반환되는 trends는 세포 밀도를 언제나 변화율 0의 stable로 보고하고, 생존율은 90 % 미만이면 고정값 −0.5의 decreasing으로 보고한다. predictedHarvest는 한 번도 설정되지 않는다. 운영용 모니터라면 이 필드들을 판단 근거로 쓰기 전에, 예를 들어 히스토리안의 TimeSeriesPoint 계열로부터 추세를 직접 계산해야 한다.
  3. 상태를 기억하지 않는다. 호출마다 스냅숏 하나를 평가한다. 이탈이 10초 지속됐는지 10시간 지속됐는지, 알람이 이미 발생해 확인되었는지, 해당 값이 지금 단계에서 예상되는 값인지 알지 못한다. 지속 조건(일정 시간 유지되어야 알람 발생), 중복 제거, 단계별 한계값은 이 함수를 감싸는 서비스가 맡아야 한다.

종합 판정 규칙은 단순하다. 치명 소견이 하나라도 있으면 전체 상태는 critical, 경고가 둘을 넘으면 warning, 경고가 하나나 둘이면 acceptable, 없으면 optimal이다. 따라서 젖산 32 mM 같은 경고 하나는 warning이 아니라 acceptable로 종합된다. 운전자 화면은 종합 단어만이 아니라 개별 소견을 보여 주어야 한다.

7.2.4 알람 생성과 확인

아래 순서도는 SDK가 빠뜨린 단계까지 포함해 루프 한 바퀴 전체를 보여 준다. 화살표 하나하나가 감사 추적에 흔적을 남겨야 하는 메시지다.

센서/분석기        히스토리안     WIA 모니터 서비스         운전자 HMI          MES(eBR)
      │                │                  │                      │                  │
      │── 판독값 ─────▶│                  │                      │                  │
      │                │── 스냅숏 ───────▶│                      │                  │
      │                │  (집계,          │ monitorBioreactor()  │                  │
      │                │   품질 필터링)   │ → MonitoringResult   │                  │
      │                │                  │ 소견 → 코드 매핑,    │                  │
      │                │                  │ BioreactorAlarm 생성 │                  │
      │                │                  │ (acknowledged=false) │                  │
      │                │                  │── 알람 ─────────────▶│                  │
      │                │                  │                      │ 운전자 검토,     │
      │                │                  │◀── 확인 ─────────────│ 의견 기입        │
      │                │                  │   (누가, 언제, 왜)   │                  │
      │                │                  │── 알람 + 확인 ─────────────────────────▶│
      │                │                  │   배치 기록에 사건 기록                  │
      │                │◀── 알람 이력 ────┤                      │                  │

BioreactorAlarm에는 type, severity, message, timestamp, acknowledged가 있지만, 누가 언제 어떤 의견으로 확인했는지를 담을 필드는 없다. GMP 기록에서 이것들은 선택 사항이 아니다(§7.5 참조). 표준의 다음 버전이 이를 추가하기 전까지는 message에 억지로 끼워 넣기보다 구분되는 이름으로 객체를 확장하는 편이 낫다. 아래는 SDK를 감싸는 한 가지 방식의 스케치이며, 확장 필드와 소견-코드 매핑은 이 책의 제안이다.

import { BioManufacturingSDK } from './index';
import type { BioreactorStatus, BioreactorAlarm } from './types';

const sdk = new BioManufacturingSDK();

// 제안 확장: v1.0 타입에 없는 필드.
interface AuditedAlarm extends BioreactorAlarm {
  code?: 'B001' | 'B002' | 'B003' | 'B004' | 'B005' | 'B006';
  batchId: string;
  acknowledgedBy?: string;
  acknowledgedAt?: Date;
  comment?: string;
}

// SDK의 문자열 소견을 알람 유형과 명세서 오류 코드로 매핑한다.
function classify(text: string): Pick<AuditedAlarm, 'type' | 'code'> {
  if (/viability/i.test(text)) return { type: 'viability', code: 'B001' };
  if (/lactate/i.test(text))   return { type: 'other',     code: 'B002' };
  if (/^pH/i.test(text))       return { type: 'pH',        code: 'B004' };
  if (/temperature/i.test(text)) return { type: 'temperature' };
  if (/^DO/i.test(text))       return { type: 'DO' };
  return { type: 'other' };
}

function evaluate(batchId: string, snap: BioreactorStatus): AuditedAlarm[] {
  const result = sdk.monitorBioreactor(snap);
  const make = (text: string, severity: 'warning' | 'critical') => ({
    ...classify(text), severity, message: text, batchId,
    timestamp: snap.timestamp, acknowledged: false,
  });
  return [
    ...result.criticalAlarms.map(t => make(t, 'critical')),
    ...result.warnings.map(t => make(t, 'warning')),
  ];
}

메시지 문자열로 분류하는 방식은 깨지기 쉽다. 여기서 보여 주는 이유는 v1.0이 더 나은 수단을 제공하지 않기 때문일 뿐이다. 더 견고한 구현이라면 임계값을 직접 다시 평가하거나, 모니터가 파라미터 이름과 오류 코드를 담은 구조화된 소견을 반환하도록 표준을 개정해야 한다. 이 변경은 제8장의 정오표 제안 목록에 들어 있다.

7.3 제어 계층

7.3.1 PID 루프

명세서 §6.2.1은 고전적인 PID 식 u(t) = Kp·e(t) + Ki·∫e(t)dt + Kd·de(t)/dt (e(t) = 설정값 − 측정값)를 제시하고 용도로 pH, 용존 산소, 온도, 액위 제어를 든다. 루프마다 고유한 특성이 있고, 이는 하류에서 데이터를 해석하는 방식에 영향을 준다.

WIA 계층이 받는 기록과 관련해 잘 알려진 PID의 함정이 두 가지 있다. 기체 공급 중단처럼 장시간 포화가 있었던 뒤에는 적분 와인드업 때문에 제약이 풀리는 순간 오버슈트가 생긴다. 또 미분 동작은 측정 잡음을 증폭하므로 생물공정 루프는 PI 제어기로 운전되는 경우가 많다. 따라서 스냅숏에 나타난 갑작스러운 튐이 언제나 공정 사건인 것은 아니다. 외란에서 회복 중인 제어기일 수도 있다.

7.3.2 공급 제어를 위한 모델 예측 제어

명세서 §6.2.2는 모델 예측 제어(MPC)를 비용 함수 J = Σ(ypred − ytarget)² + λ·Σ(Δu)²로 설명하고, 적용 분야로 공급 속도 최적화, 다변수 제어, 제약 처리를 든다. 첫째 항은 예측 구간에 걸친 출력(예: 포도당, VCD)의 목표 대비 편차를 벌하고, 둘째 항은 조작 변수(보통 공급 속도)의 큰 변화를 벌한다. 이동 억제 계수 λ는 응답성과 매끄러움을 맞바꾼다. λ가 작으면 제어기가 예측 오차를 하나하나 쫓아가고, 크면 신중해진다.

유가식 배양에서 MPC가 매력적인 이유는 공정이 비선형이고 시간에 따라 변하며, 용기의 최대 작업 부피, 세포가 굶는 최소 포도당 농도, 삼투압 상한 같은 강한 제약이 걸려 있기 때문이다. 그러나 제어기의 품질은 y를 예측하는 모델의 품질을 넘을 수 없다. 이런 루프를 닫는 측정값은 라만 포도당 모델 같은 소프트 센서(§7.2.1)가 제공하는 경우가 많고, 그 결과 소프트 센서의 밸리데이션이 곧바로 제어기의 밸리데이션과 묶이게 된다.

7.3.3 SDK가 멈추는 지점

WIA-BIO-015 v1.0의 어떤 부분도 설비를 구동하지 않는다. monitorBioreactor는 "Adjust agitation or aeration rate" 같은 권고를 반환하고, optimizeFermentation은 권장 조건을 반환하는데, 제6장에서 설명했듯 참조 코드의 그 출력은 적합된 모델의 결과가 아니라 고정된 예시 기본값이다. 두 함수 모두 설정값을 쓰지 않는다.

이것이 올바른 경계다. 제어 루프는 설비 가까이의 분산 제어 시스템(DCS)에서, 그 목적으로 적격성 평가를 받은 하드웨어와 소프트웨어 위에서 돈다. 나중에 조직이 상위 애플리케이션, 예컨대 공급 속도를 조정하는 MPC가 설정값을 쓰도록 결정한다면, 그 애플리케이션은 제어 시스템의 일부가 되어 DCS와 동일한 적격성 평가, 변경 관리, 밸리데이션 대상이 된다. 표준의 역할은 그런 결정이 소비하고 생산하는 데이터를 기술하는 것이지 결정을 내리는 것이 아니다.

계층대표 기능시간 규모(자릿수 예시)설비에 쓰는가?
기본 조절 제어(DCS)pH·DO·온도·액위 PID 루프초 단위예
고급 제어(선택)공급 속도 MPC, 다변수 제약분에서 시간 단위밸리데이션되었다면 DCS 설정값을 통해 예
WIA 모니터 서비스스냅숏에 대한 monitorBioreactor, 알람, 추세스냅숏마다(예: 몇 분 간격)아니오, 권고 전용
최적화·검토optimizeFermentation, DOE, 배치 비교배치와 배치 사이아니오, 공정 개발과 변경 관리로 연결

7.4 통합 아키텍처

7.4.1 공장 계층 구조 속의 표준

제조 IT는 관례적으로 ISA-95(국제 표준으로는 IEC 62264)의 기능 수준으로 설명한다. 수준 0–1은 물리 공정과 그 센서·구동기, 수준 2는 감시와 제어(DCS, SCADA, HMI), 수준 3은 제조 운영 관리(MES, LIMS, 히스토리안 서비스), 수준 4는 경영 계획(ERP)이다. 배치 중심의 제어 레시피는 흔히 ISA-88(IEC 61512)에 따라 구조화한다. WIA-BIO-015는 두 표준 어느 것도 인용하지 않지만, 표준의 객체를 이 수준에 대응시켜 보면 각 객체를 어느 시스템이 만들고 어느 시스템이 소비해야 하는지가 분명해진다.

WIA 모니터 서비스는 수준 2와 수준 3의 경계에 놓인다. 제어 계층에서 히스토리안이 이미 수집한 공정 데이터를 읽고, MES 전자 배치 기록(eBR)과 LIMS 같은 수준 3 시스템이 검토와 출하에 쓰는 파생 기록, 곧 모니터링 결과·알람·배치 요약을 쓴다.

WIA 객체생산 시스템소비 시스템비고
SensorReadingDCS/SCADA를 거친 센서·분석기, 히스토리안에 저장WIA 모니터 서비스(집계)원시 기록, 변경 없이 보존
BioreactorConfig엔지니어링/설비 기준정보모니터 서비스, MES변경은 변경 관리 대상
BioreactorStatus모니터 서비스(집계 스냅숏)monitorBioreactor, HMI, 히스토리안파생 기록, 판독값까지 추적 가능해야 함
MonitoringResultmonitorBioreactorHMI, 알람 관리스냅숏 하나에 대한 무상태 평가
BioreactorAlarm모니터 서비스(소견에서 생성)HMI(확인), MES eBRv1.0 이상의 감사 필드 필요(§7.2.4)
ParameterTrend / TimeSeriesPoint히스토리안, 추세 서비스HMI, 수확 판단SDK 추세는 자리표시자
BatchSummaryMES(로트 추적), 수확 시 모니터가 갱신ERP, QA 검토, 보고§7.1.4의 로트 상태 기계
PurificationProtocol공정 개발(designPurification), MBR로 승인MES(하류 공정 레시피 실행)참조 출력은 예시
QualityControlResultLIMSMES(출하), QA, ERPCQA, CoA 참조, 일탈 포함
ValidationResult검토 도구의 validateBatchQA 검토적합성 플래그 일부가 자리표시자(§7.6)

7.4.2 전송과 직렬화

표준은 데이터 구조와 함수 시그니처를 정의할 뿐, 전송 방식·메시지 봉투·엔드포인트는 정하지 않는다. PHASE 문서에 등장하는 REST 기본 URL, 요청 한도, OAuth 구성은 이 표준에 고유하지 않은 범용 문구이므로 표준의 일부로 취급하면 안 된다. 실제로는 수준 2 데이터가 OPC UA(IEC 62541) 같은 산업용 프로토콜로 히스토리안에 수집되고, 수준 3 시스템들은 각자의 인터페이스나 메시지 브로커로 기록을 주고받는 경우가 많다. 전송이 무엇이든 TypeScript 타입이 대신 정해 주지 않는 직렬화 결정 몇 가지는 명시적으로 내려야 한다.

모니터 서비스와 히스토리안 사이에서 주고받을 수 있는 스냅숏의 예:

{
  "reactorId": "BR-2000-01",
  "timestamp": "2026-03-19T06:00:00Z",
  "conditions": {
    "temperature": 36.8,
    "pH": 7.02,
    "dissolvedOxygen": 40,
    "agitation": 90,
    "pressure": 0.3
  },
  "metrics": {
    "cellDensity": 1.4e7,
    "viability": 96.5,
    "productConcentration": 1.1,
    "glucose": 4.2,
    "lactate": 32.0,
    "glutamine": 2.1,
    "ammonia": 5.4
  },
  "phase": "exponential",
  "alarms": [],
  "status": "running"
}

이 예의 값은 모두 예시다. 젖산이 SDK 경고 임계값을 넘었는데도 alarms가 비어 있다는 점에 주목하라. 스냅숏은 측정된 상태를 기술하고, 알람은 그 뒤에 모니터링 결과로부터 만들어진다. 알람을 나중에 스냅숏에 다시 써 넣을지, 별도 레코드로만 저장할지는 구현 선택이며, 문서화하고 일관되게 적용해야 한다.

7.4.3 다른 WIA 표준

README는 통합 상대로 네 가지 WIA 표준을 든다. 의도 기반 최적화를 위한 WIA-INTENT, API 게이트웨이인 WIA-OMNI-API, 사이트 간 협업을 위한 WIA-SOCIAL, 실시간 공정 데이터 관리를 위한 WIA-DATA다. 명세서의 참고 목록에도 WIA-DATA와 WIA-INTENT가 있다. 그러나 v1.0에는 이들 중 어느 것과의 인터페이스도 정의되어 있지 않다. 이들은 향후 프로파일이 연결될 수 있는 자리, 예컨대 위 표에서 히스토리안 쪽을 맡을 WIA-DATA 정도로 이해하는 것이 맞으며, 고객이나 심사자에게 작동하는 통합으로 소개해서는 안 된다.

7.5 데이터 완전성과 보안

7.5.1 WIA 객체에 적용한 ALCOA+

규제 당국은 종이든 전자든 GMP 기록이 ALCOA+로 요약되는 데이터 완전성 원칙을 충족하기를 기대한다. 귀속성(attributable), 판독성(legible), 동시성(contemporaneous), 원본성(original), 정확성(accurate)에 완전성(complete), 일관성(consistent), 지속성(enduring), 가용성(available)이 더해진 것이다. 전자 기록에 관련된 규정으로는 미국의 21 CFR Part 11과 EU GMP 가이드의 Annex 11(컴퓨터화 시스템)이 있다. WIA-BIO-015는 데이터 완전성을 명시적으로 다루지 않으므로, 아래 표는 표준의 객체가 각 원칙에 얼마나 부합하는지와 구현체가 무엇을 더해야 하는지를 보여 준다.

원칙배치 기록에서의 의미v1.0 객체의 지원추가할 것
귀속성누가, 무엇이 기록을 만들거나 바꿨는가SensorReading.sensorId가 기기를 식별, 사용자 필드 없음알람·확인·수기 입력에 사용자 신원
판독성보존 기간 내내 읽을 수 있음단위가 문서화된 평문 JSON저장 기록에 스키마 버전 표기
동시성사건이 일어난 때 기록됨판독값·상태·알람의 timestamp시계 동기화, 채취 시각과 결과 시각 분리
원본성최초 기록 보존다루지 않음원시 판독값 보존, 스냅숏은 파생 사본
정확성정확하고 검증됨판독값의 calibrated, quality교정 기록, 소프트 센서 모델 버전
완전성아무것도 조용히 삭제되지 않음다루지 않음추가 전용 감사 추적, 삭제 금지 또는 기록
일관성시간 순서와 규칙의 통일필드별 단위 고정단일 시간 기준, 통일된 직렬화
지속성보존 기간 동안 유지됨다루지 않음백업된 저장소, QA가 정한 보존 정책
가용성검토·실사 시 조회 가능다루지 않음batchId와 reactorId로 색인

7.5.2 감사 추적

감사 추적은 GMP 관련 기록의 생성·수정·삭제마다 네 가지 질문에 답한다. 누가 했는가, 무엇이 바뀌었는가(이전 값과 새 값), 언제, 왜. WIA 구현에서 감사 추적이 분명히 필요한 기록은 알람 확인, 운전자가 직접 입력한 앳라인 결과 같은 수기 입력, BatchSummary.status와 qualityStatus의 변경, 모니터가 쓰는 임계값이나 레시피 변수의 변경, 그리고 QualityControlResult의 모든 수정이다. 감사 추적은 사용자가 아니라 시스템이 생성해야 하며, 그 기록 대상이 되는 사람이 수정할 수 없어야 한다.

7.5.3 시간 동기화

센서, 분석기, 모니터 서비스, MES의 데이터를 합친 배치 기록은 이들의 시계가 일치할 때만 일관성을 갖는다. 서버 시각을 맞추는 일반적인 수단은 NTP(Network Time Protocol, RFC 5905)이며, 제어망에서 더 정밀한 정렬이 필요하면 PTP(Precision Time Protocol, IEEE 1588)를 쓸 수 있다. 시각은 UTC로 저장하고, 시계 동기화 상태 자체도 감시해야 한다. 알람이 그 원인이 된 판독값보다 먼저 일어난 것처럼 보이면 검토자는 기록 전체를 신뢰하기 어렵다.

7.5.4 접근 통제와 보안

배치 시스템에는 역할 기반 접근 통제가 자연스러운 모델이다. 운전자는 알람을 확인하고 데이터를 입력하며, 감독자는 배치 기록 안의 조치를 승인하고, 품질 보증 부서는 검토하고 출하하며, 관리자는 구성을 관리하되 생산 데이터를 바꿀 수는 없어야 한다. 결과를 기록한 사람과 승인하는 사람을 달리하는 직무 분리는 보안상의 미덕이 아니라 GMP의 기대 사항이다. 전자 서명을 쓴다면 서명은 해당 기록과 연결되어야 하고, 서명자·일시·서명의 의미를 표시해야 한다.

PHASE-4 문서는 저장 데이터 암호화(AES-256)와 전송 구간 암호화(TLS 1.3), 역할 기반 접근, 다중 인증, 포괄적 감사 로깅을 열거한다. 이는 합리적인 기본 조치이며 비규범적 지침으로 활용할 수 있다. 다만 같은 문서는 다른 표준 식별자를 달고 있고, 바이오 제조와 무관한 임상 지표와 개인정보 관련 문구를 담고 있으므로 WIA-BIO-015의 요구 사항으로 인용해서는 안 된다. 제어망 자체에 대해서는 산업 자동화·제어 시스템 보안을 다루는 IEC 62443 시리즈가 수준 2와 수준 3 사이의 구역(zone)과 도관(conduit) 설계에 적합한 참고 표준이다.

7.6 배치 기록과 변경 관리

7.6.1 마스터 제조 기록과 배치 제조 기록

명세서 §8.1.1은 필수 문서 여섯 가지를 든다. 마스터 배치 기록(MBR), 배치 제조 기록(BPR), 일탈 보고서, 변경 관리, 환경 모니터링, 설비 일지다. MBR은 승인된 지시서로, 한 제품의 공정 단계, 변수와 허용 범위, 시료 채취 지점, 공정 중 관리를 정의한다. BPR은 그 지시서에 따라 특정 배치 하나를 실행하며 작성해 나가는 실행 기록이다. 전자 배치 기록 시스템에서 MBR은 버전이 매겨진 레시피에, BPR은 한 batchId에 대한 그 레시피의 실행 인스턴스에 해당한다.

이 구분은 WIA 모니터가 한계값을 어디서 가져와야 하는지를 결정한다. 참조 SDK의 임계값은 고정 상수다. GMP 환경에서 의미 있는 한계값은 해당 제품의 MBR에 승인된 값이며, 다른 숫자를 쓰는 모니터는 배치 기록과 대응하지 않는 알람을 만든다. 실무적으로는 SDK 임계값을 기본값으로 두고 제품별 한계값을 승인된 레시피에서 불러오며, 평가마다 어느 레시피 버전이 적용되었는지 기록하는 것이 좋다.

7.6.2 WIA 객체가 §8.1.1 기록을 담는 방식

§8.1.1 기록주 기록 시스템v1.0의 WIA 담체공백
마스터 배치 기록MES 레시피 관리없음. PurificationProtocol로 하류 공정 단계는 기술 가능레시피·버전 객체 없음
배치 제조 기록MES eBRBatchSummary, 스냅숏, 알람기록에서 MBR 버전으로의 연결 없음
일탈 보고서품질 경영 시스템QualityControlResult.deviations(문자열)식별자·분류·종결 상태 없음
변경 관리품질 경영 시스템없음임계값·레시피 변경이 모델링되지 않음
환경 모니터링EM / LIMS없음객체 모델 범위 밖
설비 일지보전 시스템(CMMS), DCSBioreactorConfig, B006 설비 고장사용·세척·교정 일지 없음
문서 적합성QA 검토ValidationResult.compliance.documentation입력 플래그를 되풀이할 뿐(아래 참조)

deviations 배열은 평문 문자열 목록이다. 각 문자열 앞에 품질 경영 시스템의 일탈 식별자를 적는 관례, 예컨대 "DEV-0412: lactate above warning limit day 5, feed reduced per MBR"처럼 쓰는 방식을 따르면 QC 결과가 관리 기록을 복제하지 않고 가리키게 된다.

7.6.3 ValidationResult.compliance를 바르게 읽기

validateBatch는 불리언 네 개로 된 compliance 객체를 반환하며, 이를 대시보드에 초록색 체크로 띄우고 싶은 유혹이 생긴다. 참조 구현은 이 값들을 다음과 같이 계산한다. gmp는 차단 오류가 없거나 GMP가 요구되지 않았으면 참이다. cqas는 차단 오류가 없으면 참인데, 이 함수에서 차단 오류란 역가와 생존율 검사뿐이다. sterility는 실제 무균 시험이 필요하다는 코드 주석과 함께 언제나 참이다. documentation은 입력 gmpRequired를 그대로 되돌려 줄 뿐이다. 이 값들은 어느 것도 증거가 아니다. 실제 구현이라면 LIMS 결과와 배치 기록 검토 결과를 연결해야 할 자리를 표시하는 자리표시자다. 이를 품질 검토자에게 적합성 상태로 보여 주면 오해를 부른다.

7.6.4 모니터링 계층의 변경 관리

모니터 서비스가 GMP 판단에 쓰이기 시작하면 그 구성도 밸리데이션된 상태의 일부가 된다. 경고 한계값, 단계 판정 규칙, 라만 값 뒤의 소프트 센서 모델, §7.2.4의 소견-코드 매핑을 바꾸는 일은 모두 효력 발생 전에 평가·승인과 필요 시 재검증을 거쳐야 하는 변경이다. 구성에 버전을 매기고 서비스가 저장하는 각 MonitoringResult에 그 버전을 기록해 두면, 지난 어느 배치에서든 어떤 규칙이 어떤 알람을 만들었는지 보여 줄 수 있다.

7.7 통합 사례: 2,000 L CHO 유가식 배양

다음 시나리오는 CHO 세포로 만드는 단일클론항체 한 배치를 이 장에서 설명한 시스템들을 따라 추적한다. 모든 수치는 예시다. 그럴듯하고 서로 모순되지 않도록 골랐을 뿐, 특정 공정이나 벤치마크를 나타내지 않는다.

7.7.1 종배양 확장과 접종

워킹 셀 뱅크 바이알을 해동해 진탕 플라스크와 점점 커지는 종배양 생물반응기(예: 20 L, 200 L)를 거쳐 확장한 뒤 2,000 L 생산 용기로 옮긴다. 종배양 단계 하나하나도 자체 스냅숏을 갖는 작은 배치다. 생산 배치의 BatchSummary는 생산 용기에 접종하는 시점에 status: 'running'으로 생성되고, 그 startDate가 0일차가 된다. 첫 스냅숏은 phase: 'inoculation'으로 기록되며, 접종 밀도와 생존율이 MBR의 범위 안에 있는지 확인한다.

7.7.2 일일 스냅숏

온라인 값은 연속으로 들어오고 앳라인 시료는 하루 한 번 채취한다. 모니터 서비스는 앳라인 결과가 나올 때마다 스냅숏을 만들고 monitorBioreactor를 실행한다. 배치 일부를 발췌하면 다음과 같다.

일차VCD (cells/mL)생존율 (%)포도당 (g/L)젖산 (mM)역가 (g/L)단계모니터 상태
00.5×106986.020.0inoculationoptimal
34.0×106984.8180.2exponentialoptimal
51.4×10796.54.2321.1exponentialacceptable(경고 1건)
72.0×107953.5212.0stationaryoptimal
101.9×107883.0123.3stationaryoptimal
121.6×107783.2104.1deathacceptable(경고 1건)
131.4×107723.494.2death → harvestacceptable(경고 1건)

7.7.3 5일차의 젖산 사건

5일차에 앳라인 분석기가 젖산 32 mM을 보고한다. §7.4.2에 보인 스냅숏이 평가되고, 소견은 "Lactate accumulating: 32.0 mM" 경고 하나뿐이므로 전체 상태는 acceptable이다. 모니터 서비스는 이 소견을 B002(높은 젖산)로 분류하고, severity: 'warning', acknowledged: false인 BioreactorAlarm을 만들어 운전자 화면으로 보낸다.

명세서가 B002에 대해 정한 조치는 "포도당 공급 감소"다. 운전자가 일탈을 제기하지 않고 이 조치를 할 수 있는지는 MBR에 달려 있다. 레시피가 젖산에 대응해 정해진 범위 안에서 포도당 공급을 조정하도록 허용한다면, 공급 감소는 확인 기록과 함께 남기는 통상적인 공정 중 조치다. 허용하지 않는다면 그 조정은 품질 시스템에 일탈로 등록하고 배치 기록에서 참조해야 한다. 이 시나리오에서는 MBR이 조정을 허용한다. 운전자는 의견을 달아 알람을 확인하고, DCS를 통해 공급 설정값을 낮추며, 확인·설정값 변경·사유가 모두 eBR에 기록된다. 7일차에는 젖산이 21 mM으로 떨어져 알람 조건이 해소된다. 이는 CHO 배양에서 성장이 둔해지면 흔히 나타나는, 젖산을 소비하는 대사 전환과 부합한다.

두 가지 세부 사항이 앞서 설명한 내용을 보여 준다. 이 사건은 종합 상태에서 acceptable로만 드러나므로, 종합 상태만 보여 주는 화면이었다면 묻혀 버렸을 것이다(§7.2.3). 또 monitorBioreactor는 상태를 기억하지 않으므로, 7일차에 이전 경고가 더는 유효하지 않음을 알아보고 해소를 기록하는 주체는 SDK가 아니라 감싸는 서비스다.

7.7.4 수확 결정

10일차부터 생존율은 하루에 몇 퍼센트포인트씩 떨어지고, 역가는 10·12·13일차에 3.3, 4.1, 4.2 g/L로 느리게만 오른다. 12일차의 생존율 78 %는 이미 SDK의 "Viability declining" 경고를 일으킨다(경고 구간은 85 % 미만부터다). 히스토리안에서 계산한 추세는 하루 안팎이면 생존율이 70 %를 밑돌아 경고가 치명 알람으로 바뀔 것이라고 예측한다. 역가는 분석 변동 범위 안에서 평탄해져 "최대 역가 도달" 기준을 충족하고, 13일차는 10–14일차 창 안에 있다. 감독자는 치명 임계값에 도달하기 전인 13일차에 수확하기로 결정한다.

반응기 단계는 harvest가 되고 배치는 harvested로 넘어간다. 수확 시 작업 부피를 2,000 L로 가정하면(용기를 가득 채우지 않은 상태로 시작해 공급으로 채워 간다) 요약 필드는 다음과 같다.

totalProduct = finalTiter × volume
             = 4.2 g/L × 2,000 L = 8,400 g

productivity (calculateProductivity, 초기 0 g/L, cultureTime 312 h)
  value  = 4.2 / 312       = 0.0135 g/L/h
  perDay = 0.0135 × 24     = 0.323 g/L/day   → 성능 등급 "fair"

이 등급 이름은 참조 SDK의 등급 구간(0.8, 0.5, 0.3 g/L/day 초과)에서 나온 것으로, 산업 벤치마크가 아니라 표준 자체의 분류다. BatchSummary.productivity에는 §7.1.4의 권고대로 일 단위 값 0.323을 넣는다.

7.7.5 정제 설계와 실행

이 제품의 하류 공정 순서는 공정 개발 단계에서 일부 designPurification의 도움을 받아 정해졌고 MBR로 승인되었다. 이 배치에 대해 호출한다면 다음과 같다.

const protocol = sdk.designPurification({
  productType: 'antibody',
  scale: 2000,                 // 수확액 L
  startingConcentration: 4.2,  // g/L
  targetPurity: 99,            // %
  targetRecovery: 70,          // %
});
// 참조 코드는 Protein A 레진 부피를 scale × concentration / 40 으로 잡는다.
// 즉 2000 × 4.2 / 40 = 210 L (1회 적재 기준).

주석의 레진 부피는 참조 구현이 가정한 동적 결합 용량 40 g/L와 1회 적재 가정에서 그대로 나온다. 실제 공정은 보통 더 작은 컬럼을 여러 번 순환시키며, 선택한 체류 시간에서 측정한 동적 결합 용량으로 크기를 정한다. 따라서 이 출력은 설계가 아니라 논의의 출발점이다. 함수가 돌려주는 회수율, 순도, 소요 시간, 비용은 제6장에서 설명했듯 예시 기본값이다. 통합 관점에서 중요한 것은 실행된 하류 공정 단계가 승인된 PurificationProtocol에 대응해 기록되고, 청징 수확액을 포획 컬럼에 적재할 때 BatchSummary.status가 purifying이 된다는 점이다.

7.7.6 QC와 출하

원료의약품 충전이 끝나면 LIMS가 출하 시험 결과를 QualityControlResult로 보고한다. 예시 mAb 규격으로 표시한 한계값을 쓴 축약 예는 다음과 같다.

{
  "batchId": "MAB-2026-017",
  "product": "Example mAb",
  "testDate": "2026-04-02T10:30:00Z",
  "cqas": [
    { "name": "Monomer purity (SEC)", "value": 99.1, "unit": "%",
      "lsl": 95.0, "inSpec": true, "criticality": "high" },
    { "name": "Host cell protein", "value": 18, "unit": "ng/mg",
      "usl": 100, "inSpec": true, "criticality": "high" },
    { "name": "Endotoxin", "value": 0.2, "unit": "EU/mg",
      "usl": 5, "inSpec": true, "criticality": "high" }
  ],
  "status": "pass",
  "coa": "COA-MAB-2026-017",
  "deviations": [
    "DEV-0412: lactate above warning limit day 5, feed reduced per MBR (closed, no impact)"
  ]
}

여기 나온 한계값은 가상의 항체 하나를 위한 예시 값이다. 실제 규격은 제품마다 다르며 품목 허가에서 정해진다. 일탈 문자열은 젖산 사건을 가리키는데, 이 시나리오에서 그 사건은 MBR 범위 안에서 처리되어 제품 영향 없이 종결되었다. 이를 포함해 두면 QC 기록과 배치 기록이 서로 일관된다. 알람과 일탈에 초점을 둔 예외 검토(review by exception) 방식으로 QA가 eBR을 검토하고 나면 배치가 출하된다. BatchSummary.status는 complete, qualityStatus는 pass가 된다.

7.7.7 메시지 타임라인으로 본 시나리오

시점사건기록되는 객체주체
0일차생산 용기 접종BatchSummary(running), BioreactorStatus(inoculation)MES, 모니터 서비스
0–13일차연속 측정과 일일 측정SensorReading, 스냅숏, MonitoringResult히스토리안, 모니터 서비스
5일차젖산 경고, 공급 감소BioreactorAlarm(B002), 확인, eBR 항목모니터 서비스, 운전자, MES
13일차수확 결정BioreactorStatus(harvest), BatchSummary(harvested)감독자, MES
수확 후포획 단계 적재BatchSummary(purifying)MES
출하QC 결과와 QA 승인QualityControlResult, BatchSummary(complete, pass)LIMS, QA

장 요약