GC메디아이
인턴·신입근거: 건강 데이터 분석 결과를 기반으로 하는 B2C 서비스 및 솔루션을 개발합니다.
※ 실제 산출물이 아닌 AI 예측 시안입니다.
GC메디아이 공고는 이 자리의 수행 업무를 건강 데이터 분석 결과를 바탕으로 한 B2C 서비스 개발로 적고, 팀의 집중 과제로 대용량 의료 데이터의 실시간 처리와 동기화를 듭니다. 전국 1만 6천여 병·의원과 8천여 약국에서 데이터가 각각 들어오는 회사라, 여러 곳에서 온 같은 항목이 서로 맞는지가 이 회사 B2C 서비스의 첫 문제입니다. 이 포트폴리오는 그 대조 화면과 판정 규칙을 보여줍니다. 의료 데이터 표준과 임상 판단의 깊이는 주장하지 않고, 참고 범위는 기준표로 받아 그 값만 견줍니다.
공고가 이 인턴에게 건강 데이터 분석 결과를 바탕으로 한 B2C 서비스 개발을 맡깁니다. 그래서 산출물을 사용자가 직접 보는 앱 화면으로 잡았습니다.
EMR개발팀의 집중 과제에 대용량 의료 데이터의 실시간 처리와 동기화가 적혀 있습니다. 동기화가 밀린 항목을 사용자 화면에서 사유로 세웁니다.
AI Agent 로 코드를 쓰고 설계를 검증하는 방식이 이 자리의 일하는 방법입니다. 판정 규칙을 테스트로 고정해 도구가 쓴 코드도 같은 결과를 내는지 봅니다.
여러 의원과 약국을 다닌 사람이 자기 건강 데이터를 앱 하나로 보는 확인 화면입니다. 의원이 올린 검사 결과와 약국의 조제 기록, 앱에 떠 있는 값을 항목별로 맞대어 기준 범위를 벗어난 값, 값이 어긋난 항목, 갱신이 밀린 항목, 앱에 담기지 않은 필수 항목을 사유별로 세웁니다. 판정은 Node.js 서비스의 규칙이 계산하고 React Native 화면이 그 결과를 그립니다.
여러 의원과 약국을 오가며 자기 건강 데이터를 앱 하나로 모아 보는 사람 — 기록이 다녀온 곳마다 따로 남아, 앱에 뜬 수치가 오늘 의원에서 들은 값과 같은지 빠진 항목은 없는지 스스로는 맞춰 볼 방법이 없다
의원과 약국에서 온 항목별 값을 앱에 떠 있는 값과 기준표에 맞대면, 사용자가 다음 진료를 기다리지 않고 다시 확인할 항목을 그 자리에서 봅니다.
의원 기록 10건과 약국 기록 10건, 앱 기록 10건, 항목 기준 10건을 넣으면 다시 확인할 항목이 사유별로 뜨는 React Native 화면과 Node.js 판정 API 가 돕니다. 실제 EMR 연동은 사내 API 응답 모양을 가정한 파일 적재로 시작하고 무거운 연동은 3주차로 미룹니다.
Claude Sonnet 이 판정 결과를 사용자가 읽을 한 문장으로 옮기고 JSON 스키마로 형식을 잡습니다. Jest 로 판정 규칙을 항목마다 고정해 AI 도구가 고쳐 쓴 코드도 같은 결과를 내는지 봅니다.
판정 서비스와 적재 서비스를 컨테이너 둘로 나눠 올리고 사이를 API 로 잇습니다. 카드에서 그 항목만 다시 불러오는 요청이 붙습니다.
사용자가 의원 기록 10건과 약국 기록 10건, 앱 기록 10건을 올리면 다시 확인할 항목이 사유별로 뜨고 어느 의원이 언제 올린 값을 보고 그렇게 판정했는지 펼쳐집니다.
판정이 규칙과 맞는지 카드 15장(앱 기록 10건에, 앱에 없어 필수 항목 빠짐으로 뜨는 5건을 더한 수)을 자가채점 러너로 세어 화면 아래에 표시합니다. 정답과 데이터를 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건에서의 동작입니다.
의원 값이 비어 있거나 항목 코드가 기준표에 없는 악성·결측 입력 30종을 넣어도 항목 목록 대신 어느 줄이 왜 걸렸는지 나오고 응답 형식이 깨지지 않습니다.
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 더미데이터 자가채점이고, 실제 동기화 지연 분포와 값 차이는 GC메디아이의 실제 EMR 연동 데이터와 의료진 확인이 있어야 잽니다. 이 포트폴리오는 그 검증을 바로 돌릴 상태까지 만듭니다.
화면 아래 판정 일치 수는 제가 만든 의원·약국·앱 기록으로 낸 자가채점이라 동기화 점검의 성능 증명이 아닙니다. 면접에서는 실제 EMR 연동 기록이 들어왔을 때 이 규칙의 어디가 먼저 깨질지로 이야기를 잇습니다.
어느 항목을 다시 볼지 제가 정해 두고 잰 값이라 잘 맞는 것은 당연합니다. 그래서 약국 기록의 일수 칸이 빈 줄, 가정용 혈압계가 0 을 그대로 올린 값, 7일이나 밀린 앱 기록, 필수 항목인데 앱에 줄 자체가 없는 사람을 더미에 담아 규칙이 어디서 멈추고 어디서 판정을 내는지 카드로 드러나게 했습니다.
참고 범위는 성인 일반값 하나로 잡았습니다. 나이와 임신 여부, 복용 중인 약에 따라 같은 수치의 뜻이 달라지므로, 이 화면의 기준 밖 표시가 이상 소견을 뜻하지는 않습니다.
이 포트폴리오는 대조 화면과 판정 규칙을 보여줍니다. 의료 데이터 표준과 임상 판단의 전문성은 주장하지 않고, 판정은 기준표의 숫자와 시각 계산으로만 합니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
실제로 붙이면 의원마다 항목 코드와 단위가 달라 그 대응부터 필요합니다. 개인 건강 정보의 보관 기간과 열람 동의는 도입 단계 과제로 따로 잡습니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
의원이 진료 뒤 올린 항목별 값입니다. 사람과 항목 코드로 앱 기록과 짝지어 견주고, updated_at 이 그 의원 쪽에서 값을 마지막으로 고친 시각이라 앱이 얼마나 밀렸는지를 재는 기준이 됩니다.
| feed_no | person_id | clinic_id | clinic_name | visit_date | metric_code | metric_value | updated_at |
|---|---|---|---|---|---|---|---|
| FEED-C-001 | P-1042 | CL-0231 | 강남365의원 | 2026-03-12 | sbp | 134 | 2026-03-12T10:20 |
| FEED-C-002 | P-1042 | CL-0231 | 강남365의원 | 2026-03-12 | dbp | 86 | 2026-03-12T10:20 |
| FEED-C-003 | P-1042 | CL-0231 | 강남365의원 | 2026-03-12 | weight | 61.8 | 2026-03-12T10:20 |
| FEED-C-004 | P-1042 | CL-0231 | 강남365의원 | 2026-03-12 | fbg | 126 | 2026-03-12T10:20 |
| FEED-C-005 | P-1042 | CL-0231 | 강남365의원 | 2026-03-12 | tchol | 188 | 2026-03-12T10:20 |
아래 JSON Schema 에 정확히 맞는 의원 전송 기록 30개를 JSON 배열로 만들어 주세요.
{"type":"object","properties":{"feed_no":{"type":"string"},"person_id":{"type":"string"},"clinic_id":{"type":"string"},"clinic_name":{"type":"string"},"visit_date":{"type":"string"},"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"metric_value":{"type":["number","null"]},"updated_at":{"type":"string"}},"required":["feed_no","person_id","clinic_id","clinic_name","visit_date","metric_code","metric_value","updated_at"]}
조건: feed_no 는 FEED-C-일련 형식으로 서로 다르게 씁니다. person_id 는 P-네자리, clinic_id 는 CL-네자리로 쓰고, clinic_name 은 의원급 이름으로 씁니다. metric_value 는 항목 코드에 맞는 단위의 값으로 쓰고, updated_at 은 visit_date 당일이나 다음 날 시각으로 둡니다.
쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: metric_value 가 비어 있는 행 3건, 기준 상한을 넘긴 값 4건, 앱 기록보다 이레 이상 늦게 갱신된 행 2건, 같은 사람이 서로 다른 의원 두 곳에서 같은 항목을 올린 경우 2건. 그리고 형식 깨뜨리기 시도 3건(컬럼 이름 오타·쉼표 누락·따옴표 불일치)을 별도 파일로 만들어 화면이 어떻게 걸러 내는지 보게 합니다.
JSON 배열만 출력합니다.{"type":"object","properties":{"feed_no":{"type":"string"},"person_id":{"type":"string"},"clinic_id":{"type":"string"},"clinic_name":{"type":"string"},"visit_date":{"type":"string"},"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"metric_value":{"type":["number","null"]},"updated_at":{"type":"string"}},"required":["feed_no","person_id","clinic_id","clinic_name","visit_date","metric_code","metric_value","updated_at"]}약국이 조제할 때 남긴 기록입니다. 조제일은 남는데 며칠치인지는 안 적히는 경우가 있어 metric_value 가 비어 있는 행을 그대로 담았습니다. 앱에 필수 항목이 없을 때 그 값이 어디까지 와 있었는지를 이 표에서 봅니다.
| feed_no | person_id | pharmacy_id | pharmacy_name | event_date | metric_code | metric_value |
|---|---|---|---|---|---|---|
| FEED-P-001 | P-1042 | PH-0088 | 강남365약국 | 2026-03-09 | med_days | — |
| FEED-P-002 | P-1042 | PH-0088 | 강남365약국 | 2026-02-14 | med_days | 14 |
| FEED-P-003 | P-2077 | PH-0141 | 새봄약국 | 2026-03-11 | med_days | 7 |
| FEED-P-004 | P-3311 | PH-0512 | 한빛약국 | 2026-03-10 | med_days | 30 |
| FEED-P-005 | P-1042 | PH-0088 | 강남365약국 | 2026-01-20 | med_days | 28 |
아래 JSON Schema 에 정확히 맞는 약국 조제 기록 25개를 JSON 배열로 만들어 주세요.
{"type":"object","properties":{"feed_no":{"type":"string"},"person_id":{"type":"string"},"pharmacy_id":{"type":"string"},"pharmacy_name":{"type":"string"},"event_date":{"type":"string"},"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"metric_value":{"type":["number","null"]}},"required":["feed_no","person_id","pharmacy_id","pharmacy_name","event_date","metric_code","metric_value"]}
조건: feed_no 는 FEED-P-일련 형식으로 서로 다르게 씁니다. metric_code 는 med_days 를 주로 쓰고, metric_value 는 1 에서 31 사이의 조제 일수로 씁니다. event_date 는 최근 넉 달 안의 날짜로 흩뿌립니다.
쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: metric_value 가 비어 있는 행 4건, 조제 일수가 하한 1 인 행 2건, 같은 사람이 한 달에 두 약국에서 조제한 경우 2건.
JSON 배열만 출력합니다.{"type":"object","properties":{"feed_no":{"type":"string"},"person_id":{"type":"string"},"pharmacy_id":{"type":"string"},"pharmacy_name":{"type":"string"},"event_date":{"type":"string"},"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"metric_value":{"type":["number","null"]}},"required":["feed_no","person_id","pharmacy_id","pharmacy_name","event_date","metric_code","metric_value"]}지금 앱 화면에 떠 있는 값입니다. 사람과 항목 코드마다 한 줄이고 synced_at 은 앱이 그 값을 받아 온 시각이라, 의원 쪽 갱신 시각과 견주면 얼마나 밀렸는지 나옵니다. 기기가 값을 못 읽어 0 으로 올라온 줄도 그대로 담았습니다.
| record_no | person_id | metric_code | metric_value | synced_at |
|---|---|---|---|---|
| REC-20260312-001 | P-1042 | fbg | 126 | 2026-03-12T08:10 |
| REC-20260312-002 | P-1042 | sbp | 118 | 2026-03-12T08:10 |
| REC-20260312-003 | P-1042 | dbp | 0 | 2026-03-12T08:10 |
| REC-20260305-004 | P-1042 | weight | 62.4 | 2026-03-05T10:20 |
| REC-20260312-005 | P-1042 | hr | 72 | 2026-03-12T08:10 |
아래 JSON Schema 에 정확히 맞는 앱 화면 기록 25개를 JSON 배열로 만들어 주세요.
{"type":"object","properties":{"record_no":{"type":"string"},"person_id":{"type":"string"},"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"metric_value":{"type":["number","null"]},"synced_at":{"type":"string"}},"required":["record_no","person_id","metric_code","metric_value","synced_at"]}
조건: record_no 는 REC-연월일-일련 형식으로 서로 다르게 씁니다. person_id 와 metric_code 의 짝은 한 번씩만 나오게 하고, metric_value 는 clinic_feed 의 같은 짝과 대체로 같되 일부만 다르게 씁니다.
쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: metric_value 가 0 으로 올라온 행 2건, 기준 범위를 벗어난 값 4건, synced_at 이 의원 갱신보다 사흘 이상 이른 행 3건, 필수 항목인데 그 사람 줄이 아예 없는 경우 2건.
JSON 배열만 출력합니다.{"type":"object","properties":{"record_no":{"type":"string"},"person_id":{"type":"string"},"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"metric_value":{"type":["number","null"]},"synced_at":{"type":"string"}},"required":["record_no","person_id","metric_code","metric_value","synced_at"]}건강 항목마다 참고 범위와 앱에 반드시 담아야 하는지, 갱신이 몇 시간까지 밀려도 되는지를 적은 기준표입니다. 판정은 이 표의 값을 읽어 계산하므로 기준이 바뀌면 코드가 아니라 이 표만 고칩니다.
| metric_code | metric_name | unit | required | ref_low | ref_high | max_sync_delay_hours |
|---|---|---|---|---|---|---|
| fbg | 공복혈당 | mg/dL | true | 70 | 99 | 24 |
| sbp | 수축기혈압 | mmHg | true | 90 | 119 | 24 |
| dbp | 이완기혈압 | mmHg | false | 60 | 79 | 24 |
| weight | 체중 | kg | false | 40 | 90 | 72 |
| bmi | 체질량지수 | kg/m2 | false | 18.5 | 24.9 | 72 |
아래 JSON Schema 에 맞는 metric_spec 행을 더 만들어 주세요. {"type":"object","properties":{"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"metric_name":{"type":"string"},"unit":{"type":"string"},"required":{"type":"boolean"},"ref_low":{"type":"number"},"ref_high":{"type":"number"},"max_sync_delay_hours":{"type":"integer","minimum":1,"maximum":336}},"required":["metric_code","metric_name","unit","required","ref_low","ref_high","max_sync_delay_hours"]} metric_code 는 건강 항목 코드이고, ref_low 와 ref_high 는 성인 참고 범위, max_sync_delay_hours 는 앱 값이 뒤처져도 되는 시간입니다.{"type":"object","properties":{"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"metric_name":{"type":"string"},"unit":{"type":"string"},"required":{"type":"boolean"},"ref_low":{"type":"number"},"ref_high":{"type":"number"},"max_sync_delay_hours":{"type":"integer","minimum":1,"maximum":336}},"required":["metric_code","metric_name","unit","required","ref_low","ref_high","max_sync_delay_hours"]}| TypeScript | 앱 화면과 판정 API 를 같은 언어로 쓰고 항목 기준표의 모양을 타입으로 잡습니다. |
| JavaScript | 적재 스크립트와 러너처럼 빌드 없이 바로 돌리는 부분에 씁니다. |
| React Native | 하단 탭 네 개와 사유별 항목 목록, 근거 펼침 화면을 만듭니다. |
| Node.js | 의원·약국·앱 세 쪽 값을 항목별로 맞대어 사유를 계산하는 API 를 세웁니다. |
| PostgreSQL | 의원 기록과 약국 기록, 앱 기록, 항목 기준 네 표를 담고 사람과 항목 단위로 조회합니다. |
| MSA | 판정 서비스와 적재 서비스를 나눠 올리고 사이를 API 로 이어 3주차에 운영합니다. |
| Jest | 판정 규칙을 항목마다 테스트로 고정해 코드를 고쳐도 결과가 그대로인지 봅니다. |
| LLM | 판정이 끝난 항목의 사유를 사용자가 읽을 한 문장으로 옮깁니다. |
| Claude | 그 한 문장을 만드는 모델로 씁니다. |
| ChatGPT | 만들어진 문장에 진단처럼 읽히는 표현이 섞였는지 세는 점검 러너로 씁니다. |
✓ pass → 여기서 멈춰도 완결입니다. 더 키우려면 안내 문장 생성과 판정 규칙 테스트를 붙입니다.
✓ pass → 여기서 멈춰도 완결입니다. 더 키우려면 서비스를 둘로 나눠 올리고 다시 불러오기를 넣습니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
verdict사유 라벨 · record_no + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
기준 안에 들고 기록도 맞음이상 없음기준 범위 밖 수치기준 밖의원 기록과 앱 값이 어긋남값 차이동기화 밀려 옛 기록갱신 밀림필수 항목 빠짐항목 없음사람과 항목 한 짝에 대해 앱 값과 의원·약국 기록, 기준표를 맞대 본 결과를 담는 카드입니다. 기준 안에 들고 기록도 맞은 항목까지 카드로 내보내 사용자가 무엇이 정상이었는지 함께 봅니다.
{"type":"object","properties":{"record_no":{"type":["string","null"]},"person_id":{"type":"string"},"metric_code":{"type":"string","enum":["fbg","sbp","dbp","weight","bmi","tchol","hba1c","med_days","hr","ldl"]},"verdict":{"type":"string","enum":["기준 안에 들고 기록도 맞음","기준 범위 밖 수치","의원 기록과 앱 값이 어긋남","동기화 밀려 옛 기록","필수 항목 빠짐"]},"delay_hours":{"type":["number","null"],"description":"clinic_feed 의 updated_at 에서 app_record 의 synced_at 을 뺀 시간이며 소수 둘째 자리까지 반올림합니다. 두 시각은 evidence 에 그대로 싣습니다. 판정과 무관하게 두 시각이 다 있으면 채웁니다 — 기준 범위 밖이나 값 차이로 판정이 갈린 항목도 얼마나 밀렸는지 이 칸으로 읽습니다. 뺀 값이 음수면 앱이 의원 기록보다 나중에 받아 온 것이라 음수 그대로 둡니다. 의원 쪽 갱신 기록이 없거나 앱에 그 항목이 아예 없으면 뺄 값이 없어 null 로 둡니다."},"summary":{"type":"string"},"evidence":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"agg":{"type":"string","enum":["count"],"description":"이 항목의 value 가 수록 행의 값이 아니라 그 컬럼으로 센 행 수임을 밝힙니다. 없으면 수록 행의 값 그대로입니다."},"value":{"type":["string","number","boolean","null"]},"quote":{"type":"string"}},"required":["field"]}},"hedge":{"type":["string","null"]}},"required":["record_no","person_id","metric_code","verdict","delay_hours","summary","evidence","hedge"]}[
{
"record_no": "REC-20260312-005",
"person_id": "P-1042",
"metric_code": "hr",
"verdict": "기준 안에 들고 기록도 맞음",
"delay_hours": 2.17,
"summary": "안정시 심박수는 앱과 강남365의원 기록이 같은 값이고 기준 범위 안입니다.",
"evidence": [
{
"field": "record_no",
"value": "REC-20260312-005",
"quote": "REC-20260312-005"
},
{
"field": "metric_value",
"value": 72
},
{
"field": "ref_low",
"value": 60
},
{
"field": "ref_high",
"value": 100
},
{
"field": "feed_no",
"value": "FEED-C-007",
"quote": "FEED-C-007"
},
{
"field": "synced_at",
"value": "2026-03-12T08:10"
},
{
"field": "updated_at",
"value": "2026-03-12T10:20"
}
],
"hedge": null
},
{
"record_no": "REC-20260312-006",
"person_id": "P-1042",
"metric_code": "tchol",
"verdict": "기준 안에 들고 기록도 맞음",
"delay_hours": 2.17,
"summary": "총콜레스테롤 188 은 기준 상한 199 아래이고 의원이 올린 값과도 같습니다.",
"evidence": [
{
"field": "record_no",
"value": "REC-20260312-006",
"quote": "REC-20260312-006"
},
{
"field": "metric_value",
"value": 188
},
{
"field": "ref_high",
"value": 199
},
{
"field": "feed_no",
"value": "FEED-C-005",
"quote": "FEED-C-005"
},
{
"field": "synced_at",
"value": "2026-03-12T08:10"
},
{
"field": "updated_at",
"value": "2026-03-12T10:20"
}
],
"hedge": null
},
{
"record_no": "REC-20260312-001",
"person_id": "P-1042",
"metric_code": "fbg",
"verdict": "기준 범위 밖 수치",
"delay_hours": 2.17,
"summary": "공복혈당 126 은 기준 범위 70에서 99 를 벗어납니다.",
"evidence": [
{
"field": "record_no",
"value": "REC-20260312-001",
"quote": "REC-20260312-001"
},
{
"field": "metric_value",
"value": 126
},
{
"field": "ref_low",
"value": 70
},
{
"field": "ref_high",
"value": 99
},
{
"field": "synced_at",
"value": "2026-03-12T08:10"
},
{
"field": "updated_at",
"value": "2026-03-12T10:20"
}
],
"hedge": "이 화면은 값이 기준 범위를 벗어났다는 사실까지만 말합니다. 진단과 처방은 의료진이 합니다."
},
{
"record_no": "REC-20260312-003",
"person_id": "P-1042",
"metric_code": "dbp",
"verdict": "기준 범위 밖 수치",
"delay_hours": 2.17,
"summary": "이완기혈압이 0 으로 올라와 기준 하한 60 아래입니다.",
"evidence": [
{
"field": "record_no",
"value": "REC-20260312-003",
"quote": "REC-20260312-003"
},
{
"field": "metric_value",
"value": 0
},
{
"field": "ref_low",
"value": 60
},
{
"field": "clinic_name",
"value": "강남365의원",
"quote": "강남365의원"
},
{
"field": "synced_at",
"value": "2026-03-12T08:10"
},
{
"field": "updated_at",
"value": "2026-03-12T10:20"
}
],
"hedge": "0 은 가정용 혈압계가 값을 못 읽고 그대로 올린 것으로 보입니다. 다시 재기 전에는 실제 수치로 읽지 않습니다."
},
{
"record_no": "REC-20260312-002",
"person_id": "P-1042",
"metric_code": "sbp",
"verdict": "의원 기록과 앱 값이 어긋남",
"delay_hours": 2.17,
"summary": "앱에는 수축기혈압 118 이 떠 있는데 강남365의원이 같은 날 올린 값은 134 입니다.",
"evidence": [
{
"field": "record_no",
"value": "REC-20260312-002",
"quote": "REC-20260312-002"
},
{
"field": "metric_value",
"value": 118
},
{
"field": "feed_no",
"value": "FEED-C-001",
"quote": "FEED-C-001"
},
{
"field": "metric_value",
"value": 134
},
{
"field": "clinic_name",
"value": "강남365의원",
"quote": "강남365의원"
},
{
"field": "synced_at",
"value": "2026-03-12T08:10"
},
{
"field": "updated_at",
"value": "2026-03-12T10:20"
}
],
"hedge": "의원 갱신과 앱 동기화가 2.17시간 차이라 기준 24시간 안이고, 그래서 밀림이 아니라 값 차이로 판정했습니다."
},
{
"record_no": "REC-20260305-004",
"person_id": "P-1042",
"metric_code": "weight",
"verdict": "동기화 밀려 옛 기록",
"delay_hours": 168,
"summary": "체중은 앱이 3월 5일에 받아 온 값 그대로인데 의원 기록은 3월 12일에 갱신돼 7일이 밀렸습니다.",
"evidence": [
{
"field": "record_no",
"value": "REC-20260305-004",
"quote": "REC-20260305-004"
},
{
"field": "synced_at",
"value": "2026-03-05T10:20"
},
{
"field": "updated_at",
"value": "2026-03-12T10:20"
},
{
"field": "max_sync_delay_hours",
"value": 72
},
{
"field": "metric_value",
"value": 62.4
}
],
"hedge": null
},
{
"record_no": null,
"person_id": "P-1042",
"metric_code": "med_days",
"verdict": "필수 항목 빠짐",
"delay_hours": null,
"summary": "복약 일수는 앱에 담아야 하는 항목인데 값이 없고, 강남365약국 기록에는 3월 9일 조제만 남아 있습니다.",
"evidence": [
{
"field": "required",
"value": true
},
{
"field": "feed_no",
"value": "FEED-P-001",
"quote": "FEED-P-001"
},
{
"field": "event_date",
"value": "2026-03-09"
},
{
"field": "metric_value",
"value": null
},
{
"field": "pharmacy_name",
"value": "강남365약국",
"quote": "강남365약국"
}
],
"hedge": "약국 기록에 조제일만 있고 일수가 비어 있어 며칠치인지는 이 화면에서 정하지 못합니다."
}
][자동 검증 · 사람 없이 러너가 돌립니다] 1. verdict 가 스키마가 선언한 다섯 값 안에 있는지 확인합니다. 2. person_id·metric_code·verdict·delay_hours·summary·evidence 필드가 샘플에 있는지 확인합니다. 3. metric_spec 의 max_sync_delay_hours 가 1 이상 336 이하 범위인지 확인합니다. 4. delay_hours 를 clinic_feed.updated_at 에서 app_record.synced_at 을 뺀 시간으로 다시 계산해 소수 둘째 자리까지 반올림한 값과 같은지 봅니다. **판정과 무관하게 두 시각이 다 있으면 채웁니다** — 기준 범위 밖이나 값 차이로 판정이 갈린 항목도 이 칸에 밀린 시간이 남고, 앱이 더 나중에 받아 왔으면 음수 그대로 둡니다. 의원 갱신 기록이 없거나 앱에 그 항목이 없으면 null 입니다. 5. evidence 의 field 가 네 데이터셋의 컬럼에 실재하는지 확인합니다. 6. evidence 의 quote 가 수록 샘플의 원문 그대로인지 확인합니다. 7. summary 가 존댓말로 끝나는지 확인합니다. 8. 조건 규칙으로 app_record 에 그 항목 자체가 없으면 record_no 와 delay_hours 는 null 입니다. 성립 사례는 복약 일수 카드이고, 불성립 사례는 REC-20260305-004 입니다. 9. clinic_feed 에서 견주는 줄은 그 사람·그 항목의 줄 가운데 updated_at 이 가장 나중인 한 줄입니다. 시각이 같으면 feed_no 가 뒤인 줄을 씁니다. 10. pharmacy_feed 도 같은 방식으로 그 사람·그 항목의 줄 가운데 event_date 가 가장 나중인 한 줄만 인용합니다. P-1042 의 복약 일수는 FEED-P-001·002·005·008 네 줄이 있고 그중 3월 9일 줄인 FEED-P-001 이 인용 대상입니다. 지난 조제 이력은 카드에 싣지 않습니다. [판정 순서 · 한 항목이 두 사유에 걸릴 때] ① metric_spec.required 가 참인데 앱에 그 항목 줄이 없으면 필수 항목 빠짐입니다. ② 값이 ref_low~ref_high 밖이면 기준 범위 밖, ③ delay_hours 가 max_sync_delay_hours 를 넘으면 동기화 밀려 옛 기록, ④ 의원 값과 앱 값이 다르면 의원 기록과 앱 값이 어긋남 차례로 보고 앞에서 걸리면 뒤는 보지 않습니다. ⑤ 어디에도 안 걸리면 기준 안에 들고 기록도 맞음입니다. 앞 사유가 뒤 사유를 설명하기 때문입니다 — 체중은 밀린 기간 동안 값이 달라진 것이라 값 차이가 아니라 밀림으로 냅니다. [수동 검증 · 사람이 봅니다] 1. 카드 문장이 진단처럼 읽히지 않고 사실만 말하는지 봅니다. 2. 기준 범위가 그 항목의 일반적인 성인 참고치와 어긋나지 않는지 봅니다. [평가 러너 · 2주차] 카드 15장(앱 기록 10건에 필수 항목 빠짐 5건)에 규칙으로 만든 정답표를 붙여 판정 일치를 세고, 갈라진 항목은 값 대조에서 갈렸는지 시각 계산에서 갈렸는지 나눠 리포트에 답니다.
근거: 건강 데이터 분석 결과를 기반으로 하는 B2C 서비스 및 솔루션을 개발합니다.