Research 도메인 모델
개요
Research 도메인의 상세한 도메인 모델을 정의합니다. 본 문서는 requirements.md 및 event-storming.md에서 합의된 용어와 규칙을 기준으로 합니다.
주의: 본 도메인 문서는 Position 기반 역할 분류를 사용하지 않습니다.
조회 스코프는 IAM 권한 평가 결과(그룹/권한) +siteId컨텍스트로 결정됩니다.
1. 도메인 엔티티(Entity)
1.1 ResearchParticipant
연구 시트에 포함되어 연구 대상으로 관리되는 사용자입니다.
식별자:
participantId: ResearchParticipant 식별자(내부)userId: 슬립큐 사용자(앱 사용자) 식별자(외부 컨텍스트 참조)siteId: 병원(Site) 식별자(외부 컨텍스트 참조)
핵심 속성:
randomizationNumber: 무작위번호(병원 단위 유니크)memo: 메모(단일 최신본)enrolledAt: 연구 시트 포함 시각removedAt: 연구 시트 제외 시각(선택)nonCompliance: 불성실 상태(파생/상태)
행동(Behavior):
enrollFromClinical(): 진료용 환자에서 연구 참여자로 포함createForResearch(): 임상 연구용 신규 등록으로 포함updateRandomizationNumber(): 무작위번호 변경(검증/중복 포함)updateMemo(): 메모 변경(최신본만)removeFromResearchList(): 연구 리스트 제외
2. 값 객체(Value Object)
2.1 RandomizationNumber
무작위번호는 연구 참여자의 식별 코드입니다.
- 유니크 스코프:
siteId + randomizationNumber - 검증: 입력이 1자 이상인 경우를 최소 요건으로 하되, 연구 종류에 따라 포맷 규칙이 확장될 수 있음
- UX: 클라이언트는 0.5초 디바운스 후 중복/유효성/가용성 메시지 표시(요구사항 참조)
2.2 Memo
연구 참여자의 특이사항 메모입니다.
- 단일 최신본만 저장
- 이력 제공하지 않음
3. 상태/열거형(Conceptual Enums)
3.1 ResearchScopeType
연구 데이터 조회 스코프의 유형입니다.
ALL_SITES: 모든 임상연구 참여 Site 조회 가능SITE_SCOPED: 본인 소속 Site 범위만 조회 가능
스코프 결정은 IAM 권한 평가 결과(그룹/권한) + siteId 컨텍스트로 이루어집니다.
4. 도메인 서비스(Domain Service)
4.1 ResearchAccessService
책임:
clinicalResearch=true여부 확인 (Site 컨텍스트 의존)- IAM 평가 결과 및
siteId컨텍스트를 기반으로 스코프 결정
4.2 CardMetricsDerivationService
책임:
- 연구 참여자 카드에 필요한 파생 지표 산출
- 산출 규칙은 Research 도메인 요구사항을 따른다.
4.3 NonComplianceEvaluationService
책임:
- 불성실 판정(수면기록률, 마지막 설문 등)을 평가하고 상태/사유를 결정
5. 읽기 모델(Read Model)
5.1 ResearchParticipantCardView
연구 홈 화면 카드 렌더링을 위한 조회 모델입니다.
구성 예시:
participant: 식별/표시 정보(이름, 생년월일, site, 담당의 등)randomizationNumber,memometrics: 치료주차, 접속 횟수/42, 설문 n/4, 수면기록 A/B, 복용 A/B, 준수율, 주차 평균(SE/WASO/TST/SOL)nonCompliance: 전체 불성실 여부 및 세부 사유(수면기록/설문)
6. 도메인 이벤트(개념 정의)
이벤트 이름/페이로드는 시스템 구현에 따라 달라질 수 있으며, 본 섹션은 도메인 수준의 개념 정의입니다.
type ISO8601 = string;
export interface ResearchParticipantImported {
type: 'research.participant.imported';
eventId: string;
timestamp: ISO8601;
payload: {
participantId: string;
userId: string;
siteId: string;
randomizationNumber: string;
enrolledAt: ISO8601;
};
}
export interface RandomizationNumberUpdated {
type: 'research.participant.randomization-number.updated';
eventId: string;
timestamp: ISO8601;
payload: {
participantId: string;
siteId: string;
randomizationNumber: string;
updatedAt: ISO8601;
};
}
export interface ParticipantMemoUpdated {
type: 'research.participant.memo.updated';
eventId: string;
timestamp: ISO8601;
payload: {
participantId: string;
memo: string;
updatedAt: ISO8601;
};
}
변경 이력
| 버전 | 날짜 | 작성자 | 변경 내용 |
|---|---|---|---|
| 0.1.0 | 2025-12-29 | jeff@weltcorp.com | 최초 작성 |