Clinical Workflow
이 문서는 Hospital-at-Home Risk Monitor 예제가 표현하는 clinical workflow를 정리합니다. 목적은 실제 진단 제품을 완성하는 것이 아니라, SaMD 제품을 만들 때 device signal, preprocessing, risk assessment, monitoring UI, alarm workflow, runtime operations가 어떤 경계로 나뉘는지 보여주는 것입니다.
1. 목적
현재 예제는 PHI-free synthetic data를 사용합니다. 실제 환자 진단 claim은 하지 않지만, 제품에 가까운 개발 기준은 유지합니다.
이 workflow는 팀원이 아래 질문에 같은 답을 하도록 만드는 기준입니다.
- device가 backend에 전달해야 하는 최소 signal evidence는 무엇인가
- preprocessing feature와 clinical risk 판단은 어디에서 분리되는가
- frontend는 어떤 상태를 표시하고, 어떤 판단을 재계산하지 않는가
- alarm acknowledge/mute 같은 clinical action은 어디에 기록되는가
- runtime model/policy/preprocessing drift는 누가 감시하는가
2. Workflow
기본 흐름은 아래와 같습니다.
Signal acquisition
-> Signal packet and quality evidence
-> Signal preprocessing
-> Risk assessment
-> Monitoring dashboard
-> Alarm acknowledgement or mute
-> Review queue and audit trail
-> Runtime drift monitoring
2-1. Signal acquisition
C/Firmware와 signal-device-simulator는 생체신호 packet을 만듭니다. 이 단계의 책임은 clinical risk 판단이 아니라 measurement integrity입니다.
포함해야 하는 evidence는 아래와 같습니다.
- timestamp
- sequence number
- PPG/ECG raw value
- SpO2, heart rate
- motion, contact quality
- dropped sample, clipped, saturated, sensor disconnected 같은 packet quality flag
Low SpO2처럼 유효한 생체신호 값이 낮은 상태와 sensor dropout처럼 측정 자체가 무효인 상태는 구분합니다.
2-2. Signal preprocessing
Rust preprocessing은 signal window를 risk model이 소비할 feature로 변환합니다. Python은 Rust Python package binding, workflow orchestration, audit context propagation을 검증하고, preprocessing algorithm의 기준 구현은 Rust core에 둡니다.
대표 feature는 아래와 같습니다.
- missing ratio
- artifact score
- SpO2 drop count
- heart rate trend
- motion burden
- baseline deviation
- preprocessing version
Preprocessing은 clinical diagnosis가 아닙니다. Python risk assessment가 사용할 evidence를 만드는 단계입니다.
2-3. Risk assessment
Python은 preprocessing feature, clinical context, risk policy, model metadata를 결합해 RiskAssessment를 만듭니다.
Python이 결정하는 것은 아래와 같습니다.
- risk score
- risk level
- risk horizon
- evidence summary
- data quality warning
- alarm severity and requested action
- review queue priority
Frontend는 이 값을 재계산하지 않습니다. Backend가 만든 판단을 사용자가 오해하지 않게 표시하는 것이 frontend의 책임입니다.
2-4. Monitoring dashboard
TypeScript runtime은 Python API의 MonitoringSnapshot과 ReviewQueueItem을 읽어 clinical UI를 구성합니다.
필수 화면 요소는 아래와 같습니다.
- waveform
- numeric vital tile
- risk score and horizon
- evidence panel
- signal quality warning
- alarm banner and audible alarm state
- acknowledge/mute action
- review queue
- model, policy, preprocessing provenance
- stale snapshot state
Stale snapshot은 clinical alarm보다 먼저 드러나야 합니다. 오래된 critical 상태를 현재 상태처럼 보이게 하면 operational risk가 커집니다.
2-5. Alarm action and audit trail
Alarm acknowledge/mute는 단순 UI state가 아닙니다. 사용자가 어떤 alarm을 어떤 시점에 처리했는지 audit trail로 남아야 합니다. 같은 acknowledge/mute가 반복되어 상태가 더 이상 바뀌지 않는 경우에도 사용자 시도는 남기되, audit event의 outcome을 no-op으로 표시해 실제 상태 전이와 구분합니다.
현재 demo의 저장소 책임은 아래처럼 둡니다.
| Store | Responsibility |
|---|---|
| PostgreSQL | signal packet, risk assessment, review queue item, alarm audit event |
| Redis | latest monitoring snapshot, alarm acknowledge/mute runtime projection |
Redis는 최신 화면 상태를 빠르게 읽기 위한 projection입니다. Clinical action 이력은 PostgreSQL의 audit event로 남깁니다.
2-6. Runtime drift monitoring
Go operator 예제는 clinical risk를 계산하지 않습니다. 배포된 runtime이 원하는 model, image, policy, preprocessing version을 따르는지 감시합니다.
RiskMonitor status는 아래를 드러냅니다.
- desired state
- observed state
- field-level drift
- runtime health
- readiness dependency state
- status condition
이 경계는 Python risk API나 TypeScript alarm UI가 Kubernetes runtime 상태를 직접 해석하지 않게 만드는 platform boundary입니다.
2-7. Storage-backed workflow
저장소가 붙어도 workflow의 중심은 database가 아니라 usecase입니다. PostgreSQL과 Redis는 domain model을 소유하지 않고, Python repository port 뒤에서 runtime state와 audit trail을 보관합니다.
Storage-backed demo는 아래 흐름을 검증합니다.
POST /signal-packets
-> ingest_signal_packet
-> risk assessment
-> PostgreSQL audit/query state
-> Redis latest monitoring projection
-> GET /monitoring-snapshot
-> alarm acknowledge/mute
-> PostgreSQL alarm audit event
이 흐름에서 단단하게 지켜야 하는 것은 SignalPacket, 고주파 waveform용 SignalFrame, RiskAssessment, MonitoringSnapshot, AlarmState, AlarmAuditEvent의 의미입니다. SQL table 이름, Redis key, connection pool, retry policy는 adapter detail입니다.
3. Architecture 기준
3-1. Clean Architecture
Workflow의 핵심 규칙은 domain/usecase에 둡니다. HTTP, MQTT, PostgreSQL, Redis, React, Zephyr, Kubernetes client는 adapter입니다.
단단하게 고정할 것은 아래입니다.
SignalPacketSignalFramePreprocessedSignalRiskAssessmentMonitoringSnapshotReviewQueueItemAlarmStateRiskMonitor
느슨하게 둘 것은 아래입니다.
- HTTP 또는 MQTT ingestion
- Rust preprocessing과 Python binding payload shape
- memory 또는 PostgreSQL/Redis repository
- Storybook fixture 또는 live API response
- fake client 또는 Kubernetes envtest
3-2. DDD
각 bounded context는 자기 언어를 유지합니다.
| Context | Owns |
|---|---|
| Device signal | sample, packet, quality, calibration |
| Preprocessing | missingness, artifact, feature extraction |
| Risk assessment | policy, evidence, alarm, review queue |
| Monitoring UI | view model, presentation state, clinician action |
| Runtime operations | desired state, observed state, drift, condition |
예를 들어 firmware가 high risk를 만들거나 frontend가 risk severity를 다시 계산하면 context가 섞입니다.
3-3. 언어별 경계
각 언어는 같은 SaMD product를 구성하지만, 같은 책임을 반복 구현하지 않습니다.
| Language | Bounded context | Hard contract | Adapter flexibility |
|---|---|---|---|
| C/Firmware | Device signal | sample, packet, quality evidence | board driver, scheduler, transport |
| Rust | Preprocessing | feature, signal quality, preprocessing version | PyO3 payload, future buffer format |
| Python | Risk workflow | risk assessment, alarm, review queue, audit context | HTTP/MQTT, memory/PostgreSQL/Redis, Rust Python package wiring |
| TypeScript | Monitoring UI | view model, freshness, alarm presentation | React theme, Storybook fixture, fetch implementation |
| Go | Runtime operations | desired/observed state, drift, condition | fake client, envtest, cluster adapter |
이 표는 구현 리뷰 기준이기도 합니다. 예를 들어 TypeScript PR에서 risk level 계산이 새로 생기거나, Go PR에서 clinical threshold를 해석하기 시작하면 경계를 다시 봐야 합니다.
3-4. TDD
Workflow 변경은 아래 순서를 기본으로 합니다.
- contract 또는 fixture를 먼저 고정합니다.
- domain/usecase test로 의미를 확인합니다.
- port를 추가하거나 확장합니다.
- adapter integration test를 추가합니다.
- app smoke로 composition을 확인합니다.
- docs와 README를 같은 PR에서 갱신합니다.
이 순서를 따르면 UI, storage, Rust Python package, Kubernetes adapter를 붙여도 clinical rule 회귀를 빠르게 구분할 수 있습니다.
3-5. 검증 증거
각 경계는 문서 설명만으로 충분하지 않습니다. 아래 evidence가 같이 있어야 다음 팀원이 같은 경계를 믿고 확장할 수 있습니다.
| Boundary | Verification evidence |
|---|---|
| Contract | JSON Schema, fixture validation, make contract/test |
| Device packet | host C tests, bare-metal host simulation, Zephyr native_sim smoke |
| Preprocessing | Rust unit/integration tests, Python Rust binding fixture tests |
| Risk workflow | Python unit/API contract tests, storage-backed integration tests |
| Monitoring UI | mapper/component tests, Storybook Vitest, browser/a11y/visual smoke |
| Runtime operations | Go unit tests, fake client test, envtest status update |
| End-to-end demo | make demo/check, make demo/check/storage |
4. 주의점
- PHI를 사용하지 않습니다.
- 실제 진단 claim을 하지 않습니다.
- alarm behavior는 제품 안전 요구사항의 축약 예시입니다.
- clinical copy, labeling, audit trail, model limitation은 실제 제품에서 별도 검토가 필요합니다.
- 현재 risk policy와 preprocessing feature는 demo evidence입니다. 임상 성능 검증을 대체하지 않습니다.
- Storage schema는 demo baseline입니다. 실제 제품에서는 migration, backup, retention, access control, PHI 분리 정책이 별도로 필요합니다.