179 lines
8.3 KiB
Plaintext
179 lines
8.3 KiB
Plaintext
!theme mono
|
|
|
|
skinparam sequenceArrowThickness 2
|
|
skinparam sequenceParticipantBorderThickness 2
|
|
skinparam sequenceActorBorderThickness 2
|
|
skinparam sequenceGroupBorderThickness 2
|
|
|
|
title Health Service 내부 시퀀스 다이어그램 (역설계 - 정상치 기준 비교 포함)
|
|
|
|
participant "HealthController" as HealthCtrl
|
|
participant "CheckupSyncUseCase" as SyncUC
|
|
participant "CheckupQueryUseCase" as QueryUC
|
|
participant "FileUploadUseCase" as FileUC
|
|
participant "HealthProfileDomainService" as HealthDomainSvc
|
|
participant "CheckupAnalysisDomainService" as AnalysisDomainSvc
|
|
participant "NormalRangeDomainService" as NormalDomainSvc
|
|
participant "HealthRepository" as HealthRepo
|
|
participant "HealthCheckupRawRepository" as RawRepo
|
|
participant "NormalRangeRepository" as NormalRepo
|
|
participant "UserServiceAdapter" as UserAdapter
|
|
participant "BlobStorageAdapter" as BlobAdapter
|
|
participant "CacheAdapter" as CacheAdapter
|
|
participant "EventPublisherAdapter" as EventAdapter
|
|
participant "PostgreSQL" as PostgreSQL
|
|
participant "Redis Cache" as Redis
|
|
participant "Azure Blob Storage" as BlobStorage
|
|
participant "Azure Service Bus" as ServiceBus
|
|
|
|
== 1. POST /api/health/checkup/sync (건강검진 결과 연동) ==
|
|
|
|
HealthCtrl -> SyncUC: syncCheckupData(userId)
|
|
|
|
SyncUC -> UserAdapter: getUserInfo(userId)
|
|
UserAdapter -> SyncUC: UserInfo 응답 (memberSerialNumber, gender 포함)
|
|
|
|
SyncUC -> RawRepo: findNhisCheckupDataByMemberSerial(memberSerialNumber)
|
|
RawRepo -> PostgreSQL: SELECT * FROM health_checkup_raw WHERE member_serial_number = ? ORDER BY reference_year DESC
|
|
PostgreSQL -> RawRepo: 건강보험공단 건강검진 원본 데이터
|
|
|
|
SyncUC -> HealthRepo: findByMemberSerialNumber(memberSerialNumber)
|
|
PostgreSQL -> HealthRepo: 기존 가공 데이터 조회
|
|
|
|
alt 기존 데이터가 없거나 더 최신 원본 데이터가 있는 경우
|
|
SyncUC -> NormalRepo: getNormalRangesByGender(userGender)
|
|
NormalRepo -> PostgreSQL: SELECT * FROM health_normal_ranges WHERE gender_code IN (0, ?) ORDER BY item_code
|
|
note right: 성별별 + 공통 정상치 기준 조회
|
|
PostgreSQL -> NormalRepo: 성별별/공통 정상치 기준 데이터
|
|
|
|
SyncUC -> AnalysisDomainSvc: transformAndAnalyzeCheckupData(rawData, normalRanges, userGender)
|
|
|
|
AnalysisDomainSvc -> AnalysisDomainSvc: validateAndConvertData(rawData)
|
|
note right: 건강보험공단 데이터 검증 및 단위 변환
|
|
|
|
AnalysisDomainSvc -> NormalDomainSvc: compareWithNormalRanges(checkupData, normalRanges)
|
|
NormalDomainSvc -> NormalDomainSvc: evaluateEachIndicator(indicators, ranges)
|
|
note right: **각 지표별 정상/주의/위험 판정**\n- BMI, 혈압, 혈당, 콜레스테롤 등\n- 성별별 기준 적용
|
|
|
|
NormalDomainSvc -> NormalDomainSvc: calculateOverallRiskLevel(indicatorResults)
|
|
note right: **종합 위험도 레벨 계산**\n- 정상: 80-100점\n- 주의: 60-79점\n- 위험: 0-59점
|
|
|
|
NormalDomainSvc -> NormalDomainSvc: identifyAbnormalIndicators(indicatorResults)
|
|
note right: 이상 항목 식별 및 JSON 배열 생성
|
|
|
|
NormalDomainSvc -> AnalysisDomainSvc: NormalRangeAnalysisResult 반환
|
|
|
|
AnalysisDomainSvc -> AnalysisDomainSvc: createHealthCheckupEntity(transformedData, analysisResult)
|
|
AnalysisDomainSvc -> SyncUC: 변환된 HealthCheckupEntity (정상치 비교 결과 포함)
|
|
|
|
SyncUC -> HealthRepo: saveOrUpdateHealthCheckup(healthCheckupEntity)
|
|
HealthRepo -> PostgreSQL: INSERT/UPDATE health_checkups
|
|
note right: 정상치 비교 결과도 함께 저장\n- abnormal_indicators: JSON 배열\n- health_score: 0-100점\n- risk_level: normal/caution/danger
|
|
PostgreSQL -> HealthRepo: 저장 완료
|
|
end
|
|
|
|
SyncUC -> CacheAdapter: invalidateUserHealthCache(userId)
|
|
CacheAdapter -> Redis: DEL health:history:{userId} health:normal:{userId}
|
|
|
|
SyncUC -> EventAdapter: publishHealthDataSyncedEvent(userId, syncResult)
|
|
EventAdapter -> ServiceBus: 건강데이터 동기화 이벤트 발행
|
|
|
|
SyncUC -> HealthCtrl: HealthSyncResponse 반환
|
|
note right: {syncedRecords, newRecords, updatedRecords, skippedRecords, lastSyncedCheckup, message}
|
|
|
|
== 2. GET /api/health/checkup/history (건강검진 이력 조회) ==
|
|
|
|
HealthCtrl -> QueryUC: getHealthCheckupHistory(userId, limit)
|
|
|
|
QueryUC -> CacheAdapter: getCachedHealthHistory(userId)
|
|
CacheAdapter -> Redis: GET health:history:{userId}
|
|
Redis -> CacheAdapter: 캐시된 데이터 또는 null
|
|
|
|
alt 캐시 미스인 경우
|
|
QueryUC -> HealthRepo: findCheckupHistoryWithDetails(userId, limit)
|
|
HealthRepo -> PostgreSQL: SELECT * FROM health_checkups WHERE user_id = ? ORDER BY reference_year DESC LIMIT ?
|
|
PostgreSQL -> HealthRepo: 건강검진 이력 데이터 (정상치 비교 결과 포함)
|
|
|
|
QueryUC -> AnalysisDomainSvc: calculateTrendAnalysis(checkupHistory)
|
|
AnalysisDomainSvc -> AnalysisDomainSvc: analyzeTrendsByIndicator(historyData)
|
|
note right: **트렌드 분석**\n- 연도별 변화 추이\n- 개선/악화 항목 식별\n- 평균 건강점수 계산
|
|
|
|
QueryUC -> CacheAdapter: cacheHealthHistory(userId, analysisResult)
|
|
CacheAdapter -> Redis: SETEX health:history:{userId} 3600 {data}
|
|
note right: 1시간 TTL로 캐싱
|
|
end
|
|
|
|
QueryUC -> HealthCtrl: HealthHistoryResponse 반환
|
|
note right: {checkupHistory, totalRecords, averageHealthScore, trendAnalysis, normalRangeReference}
|
|
|
|
== 3. POST /api/health/checkup/upload (건강검진 파일 업로드) ==
|
|
|
|
HealthCtrl -> FileUC: uploadCheckupFile(uploadRequest)
|
|
note right: {userId, fileName, fileType, fileContent}
|
|
|
|
FileUC -> FileUC: validateFileFormat(fileType, fileContent)
|
|
note right: 파일 형식 및 크기 검증 (최대 10MB)
|
|
|
|
FileUC -> BlobAdapter: uploadToAzureBlob(fileName, fileContent)
|
|
BlobAdapter -> BlobStorage: Azure Blob Storage Upload
|
|
BlobStorage -> BlobAdapter: 업로드 완료 응답
|
|
|
|
FileUC -> HealthRepo: saveFileMetadata(fileMetadata)
|
|
HealthRepo -> PostgreSQL: INSERT INTO health_files (user_id, file_name, file_url, file_type, upload_status)
|
|
PostgreSQL -> HealthRepo: 파일 메타데이터 저장 완료
|
|
|
|
FileUC -> HealthCtrl: FileUploadResponse 반환
|
|
note right: {fileId, uploadUrl, status, message}
|
|
|
|
== 4. GET /api/health/normal-ranges (정상치 기준 조회) ==
|
|
|
|
HealthCtrl -> QueryUC: getNormalRangesByGender(genderCode)
|
|
|
|
QueryUC -> CacheAdapter: getCachedNormalRanges(genderCode)
|
|
CacheAdapter -> Redis: GET normal:ranges:{genderCode}
|
|
Redis -> CacheAdapter: 캐시된 정상치 기준 또는 null
|
|
|
|
alt 캐시 미스인 경우
|
|
QueryUC -> NormalRepo: getNormalRangesByGender(genderCode)
|
|
NormalRepo -> PostgreSQL: SELECT * FROM health_normal_ranges WHERE gender_code IN (0, ?) ORDER BY item_code
|
|
PostgreSQL -> NormalRepo: 성별별/공통 정상치 기준 데이터
|
|
|
|
QueryUC -> CacheAdapter: cacheNormalRanges(genderCode, normalRanges)
|
|
CacheAdapter -> Redis: SETEX normal:ranges:{genderCode} 86400 {data}
|
|
note right: 24시간 TTL로 캐싱 (변경 빈도 낮음)
|
|
end
|
|
|
|
QueryUC -> HealthCtrl: NormalRangeResponse 반환
|
|
note right: {normalRanges: [{itemCode, itemName, genderCode, normalMin, normalMax, cautionMin, cautionMax, dangerMin, dangerMax, unit}]}
|
|
|
|
== 예외 처리 (정상치 관련 추가) ==
|
|
|
|
alt 정상치 기준 데이터 없음
|
|
NormalRepo -> AnalysisDomainSvc: NoNormalRangeFoundException
|
|
AnalysisDomainSvc -> SyncUC: 기본 정상치 기준 사용
|
|
note right: 하드코딩된 기본값으로 대체
|
|
end
|
|
|
|
alt 정상치 비교 실패
|
|
NormalDomainSvc -> AnalysisDomainSvc: NormalRangeComparisonException
|
|
AnalysisDomainSvc -> SyncUC: 정상치 비교 없이 기본 저장
|
|
note right: 기본 건강검진 데이터만 저장
|
|
end
|
|
|
|
alt 파일 업로드 실패
|
|
BlobAdapter -> FileUC: BlobStorageException
|
|
FileUC -> HealthRepo: updateUploadStatus(fileId, "FAILED")
|
|
FileUC -> HealthCtrl: 500 Internal Server Error
|
|
end
|
|
|
|
== 캐싱 전략 (정상치 관련 추가) ==
|
|
|
|
note over QueryUC, CacheAdapter
|
|
**확장된 캐싱 전략**
|
|
- 건강검진 이력 + 정상치 비교: 1시간 캐시
|
|
- 정상치 기준 데이터: 24시간 캐시 (변경 빈도 낮음)
|
|
- 건강 점수 계산 결과: 포함 (이력과 함께)
|
|
- 트렌드 분석 결과: 포함 (이력과 함께)
|
|
- 파일 메타데이터: 30분 캐시
|
|
- 정상치 기준 업데이트 시 관련 캐시 무효화
|
|
end note |