05. 도메인 모델 (as-is) — 닥터팔레트에서 관찰한 엔티티·열거값·상태 머신
상태: 통합본 v1 (2026-09-30) · 작성: S4 통합
목적: 닥터팔레트 공개 자료(제품소식·고객사례·기능 페이지·매뉴얼 영상 프레임)에서 관찰된 데이터 구조를 한곳에 모은다. 우리 앱의 to-be 모델(docs/design/domain-model.md)을 확정하기 직전의 근거 자료다.
범위: 엔티티·필드·열거값·상태 머신을 다룬다. 규칙은 06-business-rules.md, 흐름은 04-workflows.md에 있다.
표기
- 확신도: 확인 = 화면·원문에 직접 보인다 / 추정 = 정황으로 판단했다 / 미확인 = 자리만 보이고 내용은 모른다.
- 출처 태그:
A1~A6 = 텍스트 분석 파일, V1~V9 = 매뉴얼 영상 분석 파일, V#:영상-초 = 프레임, news#idx = 제품소식 게시글 번호.
- 필드명은 구현 관점에서 영문 camelCase로 옮겼다. 괄호 안은 화면에 보인 한글 라벨이다.
- 버전 표기: v2.4 = 2022-09 매뉴얼 영상(V1~V8), 2024 = 플래너 개편(news#124177982), 2025 = 2025 화면(A3·A4·A6).
0. 전체 구조 한눈에
닥터팔레트의 데이터는 환자(Patient) — 내원(Visit) — 차트 칸들을 축으로 도는 구조다. 예약(플래너)은 내원 앞에, 수납·문서·청구는 내원 뒤에 붙는다. 원내 동선은 내원의 위치(대기열) × 상태 두 축으로 표현한다 [A1 구현 시사점, V3 R17].
erDiagram
Hospital ||--o{ Member : "소속(멀티 병원)"
Hospital ||--o{ Room : "대기열·공간"
Hospital ||--o{ Patient : owns
Patient ||--o{ PatientTagLink : tags
Patient ||--o{ FamilyLink : family
Patient ||--o{ ConsentRecord : consents
Patient ||--o{ IdentityVerification : "본인확인"
Patient ||--o{ EligibilityCheck : "자격조회"
Patient ||--o{ PatientNote : "환자기록 스레드"
Patient ||--o{ Plan : "예약(플랜)"
PlanCategory ||--o{ Plan : "열·색"
Schedule ||--o{ SchedulePeriod : "기간 규칙(v2.4)"
Schedule ||--o{ Plan : "슬롯(v2.4)"
Plan |o--o| ChartDraft : "차트 초안"
Plan |o--o| Visit : "접수 전환"
ExternalBooking |o--o| Plan : "네이버·구글·여신"
ReceptionRequest |o--o| Visit : "태블릿 접수신청"
Patient ||--o{ Visit : visits
Visit ||--o{ QueueEntry : "위치×상태 이동"
Room ||--o{ QueueEntry : hosts
Visit ||--o{ ChartSection : "역할별 기록 칸"
Visit ||--o{ Diagnosis : "상병"
Visit ||--o{ OrderLine : "진단 및 처방"
Visit ||--o{ Task : "할 일"
Visit ||--o{ VisitImage : "≤30장"
Visit ||--o{ VitalSign : "임상관찰"
Visit ||--|| Charge : "진료비 산정"
Visit ||--o{ Payment : "수납·환불"
Visit ||--o{ IssuedDocument : "문서발급"
Visit ||--o{ CouponApplication : "쿠폰"
Patient ||--o{ PointLedger : "포인트"
Patient ||--o{ PrepaidLedger : "선납금"
TicketProduct ||--o{ PatientTicket : "판매"
Patient ||--o{ PatientTicket : owns
PatientTicket ||--o{ TicketUsage : "회차 차감"
OrderLine |o--o| TicketUsage : "사용 오더"
Visit ||--o{ MessageDispatch : "접수 안내"
Plan ||--o{ MessageDispatch : "예약 알림"
ClaimBatch ||--o{ ClaimStatement : "명세서"
Visit ||--o{ ClaimStatement : "원천"
1. 테넌시·조직·권한
| 엔티티 |
필드(관찰) |
확신도 |
출처 |
| Hospital |
id, name, logo, appVersion(화면 좌하단 표기) |
확인 |
V1, V2, V9 |
| HospitalInfo(설정 > 병원정보) |
탭 병원정보 · 인증정보 · 보안관리 · 연동정보 · 서비스이용현황; 서류용 상호·주소·대표자, 직인 이미지, 대표자 인장 |
확인(탭·서식) / 필드 추정 |
A4 설정, V3 서식, A1 문서 |
| Staff/User |
id, name, initials(아바타 2글자), avatarColor, loginEmail, licenseNo·licenseType(서류), 서명/인장 이미지, title(직책: 원장…), deptId |
확인 |
V1, V3 R14, A3 직원 디렉터리 |
| Member(병원 소속) |
userId, hospitalId, jobTitle(직군), dept(부서), roleIds[] |
확인(권한 화면) |
A4 권한 |
| Department |
name(의료팀·상담팀·코디팀·피부팀·간호팀) |
확인 |
A3 만족도조사 |
| Role(권한 그룹) |
name, isDefault(기본권한*), 멤버 수. 예: 소유자 · 진료 · 원무 · 원무관리자 · 멤버관리자 · 기본권한 |
확인 |
A4 권한(news#160846449) |
| RolePermission |
roleId, module(홈·차트·검사·플래너·통계…), action(아래 표) |
확인 |
A4 권한 |
| SecurityAdmin |
userId, grantedAt. IP 제한 예외 대상 |
확인 |
A4 IP |
| IpAllowRule |
ip, placeName(본점·원장님 자택…), createdBy, createdAt. 최대 100개, 관리 이력 |
확인 |
A4 IP(news#22856912) |
| PrivacyAccessLog / PrivacyDestroyLog |
설정 하위 메뉴 개인정보조회이력, 개인정보파기이력 |
확인(메뉴) / 필드 미확인 |
A4 설정 |
| DeviceSetting |
deviceId, cidModalEnabled(이 PC에서만 CID 팝업) |
확인(토글) / 식별 방식 추정 |
A2 CID |
권한 매트릭스(2025, 관찰된 세부 동작) [A4 권한 — 확인]
| 모듈 |
세부 동작 |
| 홈 |
병원 업무 수정·삭제, 공지사항 수정·삭제 |
| 차트 |
차트 삭제 · 진료기록 조회/수정 · 이미지 조회/수정 · 진단 및 처방 조회/수정 · 간호기록 조회 · 간호기록 수정·삭제 · 쿠폰내역 조회/수정 · 포인트내역 조회/수정 · 수납 조회/수정 · 문서발급 조회·수정 · 다른 사용자가 작성한 환자기록 수정·삭제 |
| 검사 |
모듈 단위 |
| 플래너 |
카테고리/스케줄 수정 · 플랜 수정·취소 · 플랜 삭제 |
| 통계 |
인사이트 조회(월간 경영 리포트) · 매출 조회 · 차트 조회 … |
- 한 사용자가 여러 역할을 갖는지,
기본권한이 신규 멤버 기본값인지는 추정이다.
- AI 상담 녹취 기록은 병원 관리자 + 해당 상담실장 본인만 열람한다(레코드 단위 접근 정책) [A3 "닫힌 기록" — 확인(원문)].
2. 병원 설정 마스터
| 엔티티 |
필드(관찰) |
확신도 |
출처 |
| Room(대기열·공간·대기리스트) |
id, name, kind, doctorId?(진료실 담당의 — 그룹 헤더 이니셜 배지), color, sortOrder |
확인 |
V1 R7, V2 R1, V5 R16 |
| VisitPurpose(방문목적) |
id, name(일반진료·아토피진료·검사·레이저치료·영양제·문서발급·상담…), order |
확인 |
V1, V5, V6 |
| SubPurpose(세부목적) |
id, purposeId, name(감기·복통·피부질환…). 다중 선택, 없는 방문목적도 있음(검사 → 비활성) |
확인 |
V6 규칙 |
| PatientTag(환자유형) |
name(VIP·지인추천·검색방문·주의환자·관심환자·외국인환자·연예인·국적…), color |
확인 |
V1 R13, V9, A3 |
| ReceptionTag(접수태그) |
자유 입력 문자열 |
확인(필드) |
A3 접수 모달 |
| Holiday |
date, name, isSubstitute(대체공휴일) — 내장 달력으로 추정 |
추정 |
V5 R6 |
| WaitingScreen(대기스크린) |
name(요일 세트, 예 월수금), rooms[], maskName, noticeText, videoUrl, chime, voiceCall |
확인 |
A6 S26~S28 |
| HospitalSetting |
maskPatientName(대기스크린), 할 일 자동 등록, 루틴 정의, 동의서 사용, CID 연동, 네이버 예약연동… |
확인(토글들) |
V5, A3, A6, A2 |
Room.kind(관찰값): 진료실(담당의 연결) · 상담실 · 레이저실/시술실 · 진료지원 · 검사실/방사선실 · 수납실 · 접수실 · 태블릿접수(가상 — 유입 채널이 대기열처럼 보임) [V1, V9 위치 그룹, A3 원내 운영].
3. 환자
3-1 Patient
| 필드 |
설명 |
확신도 |
출처 |
| chartNo |
no. + 병원별 순번 정수. 등록 시 발급. PACS 환자 ID와 같음 |
확인 |
V1 R24, V2 R23 |
| name |
v2.4 한글 최대 10자 → 2025-02 최대 60자(외국인 이름) |
확인 |
V1 R1, A4(news#158666898) |
| rrnFront / rrnBack(암호화) |
주민·외국인등록번호. 검색 결과는 뒤 첫 자리까지만, 상세 화면은 전체 표시 |
확인 |
V1 R23 |
| hasNoRrn |
주민등록번호가 없습니다. 예외 체크 |
확인 |
V1 R1, V2 R9 |
| nationality |
내국인/외국인 |
확인 |
V1 |
| sex, birthDate |
주민번호에서 파생 |
확인 |
V1 |
| phoneMain(대표연락처), phoneEmergency(비상연락처) |
|
확인 |
V1 |
| zipCode, address1, address2 |
우편번호 검색. 인사이트는 동 단위 집계 |
확인 |
V1, V9 |
| tags[] |
멀티 태그 |
확인 |
V2 R12 |
| isTemporary |
임시환자(2025-02 검색 가능) — 인적사항 없이 먼저 만든 환자 |
확인(용어) / 의미 추정 |
A4 환자 검색 |
| isNew(빨간 점) |
이름 옆 빨간 점. 신환 표시로 보이나 확정 못 함 |
추정 |
V2 R4, V9 |
| eligibilityCheckedAt |
환자정보에 자격조회 완료 시각 표시 |
확인 |
V2 R10 |
| specialCaseFlags |
헤더 칩 산정특례 영유아 |
확인(칩) |
V9, A2 |
| prepaidBalance(₩), pointBalance(P) |
접수 모달 이름 툴팁에 따로 표시 |
확인 |
A3 접수 모달 |
| lastVisitAt, firstVisitDate |
검색 결과·통계 |
확인 |
V1, V4 |
3-2 환자 부속
| 엔티티 |
필드 |
확신도 |
출처 |
| FamilyLink |
patientId, relatedPatientId, relation(형제·아빠·할머니…). 등록된 환자끼리만 연결. 헤더에 대표 가족 1~2명 + +n. 양방향 저장 여부 미확인 |
확인 / 양방향 미확인 |
V1 R12, V2 R8 |
| ConsentRecord |
patientId, type(개인정보 필수 · 마케팅 선택 · 음성 녹음 및 AI 분석 선택), required, agreed, agreedAt, channel(tablet_self · staff_verbal_attest · signed_form), attestedBy?, docVersion, withdrawnAt? — 동의하지 않은 결과도 기록, 차트에 동의서로 자동 기록 |
확인(2026 화면) |
V1 R11, A3 태블릿·녹취 동의 |
| IdentityVerification(본인확인) |
patientId, verifiedAt, method(실물신분증 · 모바일건강보험증 · 예외), qrNumber?, exemptReason?, verifiedBy, validUntil = +6개월 |
확인(2024-06) |
A2 본인확인 |
| EligibilityCheck(자격조회) |
patientId, checkedAt, eligibilityDate(자격일자), qualification(건강보험 · 의료급여1종 …), nationality, specialNotes[](특이사항 칩), trigger(등록·접수·수동), alerts[](ITS 확진자 알림 등), rawPayload |
확인 / 원문 저장 추정 |
V1 R2, A2, A5 R-42 |
| VitalSign(임상관찰기록) |
measuredAt, temperature(°C), bpSys/bpDia(mmHg), pulse(회/min), glucoseFasting·glucosePost(mg/dL), weight(kg), height(cm). v2.4는 5종(체온·체중·신장·혈압·혈당) → 2023-06 확장 |
확인 |
V1 R10, A1 외래접수 |
| PatientCaution(특이사항) |
알러지 등 방문을 넘어 유지되는 주의사항(⚙ 설정 있음) |
추정 |
A4 역할별 기록 |
| FamilyHistory / PatientDrug |
⋮ 메뉴 가족력 관리, 환자약품 관리 |
미확인 |
A4 ⋮ 메뉴 |
3-3 환자기록(직원 스레드)
| 엔티티 |
필드 |
확신도 |
출처 |
| PatientNote |
id, patientId, authorId, authorRole(원무·간호·원장·영양 칩), body, mentions[staffId], createdAt, isNotice(📢 공지 — 상단엔 최신 1건만 고정, 목록 누적), noticeAt |
확인 |
V1 R22, V2 R18, V9 |
| NoteAck |
noteId, staffId, at → 메시지 하단 ✓N |
확인 |
V2 R20 |
| NoteBookmark |
noteId, staffId — 본인 전용 |
확인 |
V2 R19 |
| Notification(멘션) |
type=mention, targetUserId, patientId, noteId, readAt. 문구 "{작성자}님이 {환자}님의 환자기록에서 나를 멘션했습니다." + [차트열기][✓확인] |
확인 |
A1 환자기록 |
- 환자기록은 방문과 무관하게 환자 단위로 누적된다 [A1]. 접수 모달·예약 모달의
주요기록/최근기록(최근 10건)에 재노출된다 [V1 F6, A2 접수 모달].
4. 예약 — 두 세대의 모델
닥터팔레트 예약은 두 모델이 공존·교체됐다. 우리 설계는 이 차이를 알고 골라야 한다.
| 구분 |
v2.4 스케줄 모델(2022) |
2024-10 이후 플래너 모델 |
| 자원 단위 |
Schedule(원장·검사 등) = 예약 그리드 컬럼 |
PlanCategory(시술·장비·의사명 자유) = 컬럼 |
| 시간 |
슬롯(간격 15/20/30분 × 정원 1~5) — 시각은 슬롯에서 선택 |
자유 시간(시작~종료, 슬롯에 묶이지 않음). 30분 눈금 표시만 |
| 운영시간 |
기간·요일 규칙 + 날짜 예외(이벤트/휴진) |
화면 미관찰(카테고리에 운영시간 개념 보이지 않음) |
| 상태 |
예약 · 접수 · 예약취소 |
요청 · 확정 · 접수 · 완료 · 취소(+노쇼 칩) · 거절 · 삭제 |
| 업무 블록 |
없음 |
업무 플랜(자리비움) |
| 외부 채널 |
없음 |
네이버(2024-02) → 구글·여신티켓(2025) |
| 근거 |
V5, V6 |
A2(news#124177982), A3, A4, A6 S20 |
VOC 표에 "슬롯 구간에 묶이지 않는 자유 시간 예약", "시작·종료 시간 설정", "플래너 시간 간격 변경"이 반영 항목으로 있다 → 슬롯 모델에서 자유 시간 모델로 의도적으로 옮겼다(확인, A2 플래너).
4-1 v2.4 스케줄 모델 [V5·V6 — 확인]
| 엔티티 |
필드 |
| Schedule |
id, name, color(10색: 블루·그린·옐로우·레드·핑크·퍼플·라임·하늘·바이올렛·연두), visitPurposeIds[], kind(의사/검사 — 추정), active |
| SchedulePeriod |
scheduleId, startDate, endDate?(없음 = "스케줄 지속됨"), bookingOpenPolicy(환자 예약 오픈 시간, 기본 "항상"), slotMinutes(15 기본, 관찰 15·20·30), slotCapacity(신규 기본 5, 관찰 1·2·5), skipLegalHolidays(기본 ✓), crmNotify(기본 OFF) |
| WeeklyHours |
weekday(월일), enabled, ranges[≤2]{start,end}. 신규 기본 월금 09:00–13:00·14:00–18:00, 토 09:00–13:00, 일 해제 |
| ScheduleDateOverride |
scheduleId, date, type(EVENT "E" 칩 — 단일 구간 / DISABLED 휴진 회색) |
| Slot(계산값) |
scheduleId, date, start, end, capacity, bookedCount — 슬롯 카드 "HH:MM-HH:MM · n" |
4-2 Plan(예약·업무 플랜) — 2024~2025 통합
| 필드 |
설명 |
확신도 |
출처 |
| id |
|
|
|
| type |
PATIENT(환자 플랜) · WORK(업무 플랜: 자리비움·메모) |
확인 |
A2 플래너, A3 |
| patientId? / guestName·guestBirthDate·guestSex |
신환 예약은 환자 레코드 없이 게스트로 저장(빨간 점, 환자 검색 탭에 안 나오고 예약현황 탭으로만 검색) |
확인(v2.4) |
V6 규칙 |
| bookerSameAsPatient, bookerName, bookerPhone |
예약자 ≠ 환자(보호자 대리) |
확인 |
V5 R11, V6 |
| date, startAt, endAt |
2024부터 시작~종료 자유 |
확인 |
A2 |
| categoryId |
컬럼(시술·장비·의사) |
확인 |
A2, A4 |
| scheduleId |
v2.4 모델 |
확인(v2.4) |
V6 |
| doctorId?, staffId?(담당자) |
폼 필드 담당의 · 담당자 |
확인 |
A2 예약 폼 |
| queueId?(대기리스트) |
내원 시 들어갈 대기열(예 진료실1) |
확인(필드) / 자동 배정 추정 |
A2 예약 폼 |
| visitPurposeId, subPurposeIds[] |
|
확인 |
V6, A2 |
| questionnaireId? |
발송할 문진 |
확인 |
A2 |
| memo |
0/600자. 메디톡에서 만들면 상담 메모가 자동으로 채워짐 |
확인 |
A3 예약 폼 |
| suppressCrm |
☐ CRM 메시지 보내지 않기 |
확인(체크박스) / 효과 추정 |
A2, A3 |
| channel |
INTERNAL(○ 자체) · NAVER(N) · GOOGLE(G) · YEOSHIN · APP(보라 ◯ — 메디패스 추정) · PHONE(📞) |
확인(아이콘) |
A2, A3 |
| status |
아래 상태 머신 |
확인 |
A3, A6 S20 |
| cancelReason |
자유 입력(선택), 사후 수정 가능. 플래너는 취소:노쇼 칩 |
확인 |
V6 S5, A2 |
| colorOverride / 자동 색 |
카드 색 수동 지정(◐) + 색상 자동화 규칙(접수·완료·지각·대기상태) |
확인(규칙 존재) / 규칙 상세 추정 |
A2, A4 |
| vip |
카드 VIP 배지(환자 태그 파생) |
확인 |
A4 |
| createdBy/At, updatedBy/At |
|
추정 |
|
| 엔티티 |
필드 |
확신도 |
출처 |
| PlanCategory |
name, color, hidden(눈 아이콘), order, 헤더 당일 건수 |
확인 |
A2, A4 |
| PlanLog(최근 플랜) |
planId, action(등록·수정·취소·삭제·거절·확정·요청), actorId, at, channel |
확인 |
A2, A4 |
| PlanColorRule |
trigger(접수·완료·지각·대기상태), color |
확인(메뉴·알리미) / 필드 추정 |
A4 |
| ChartDraft(차트 초안) |
planId, plannedVisitDate, notes{consult, care, special}, clinicalNote, orders[], (수납 사전 작성) — 내원이력 초안 섹션, 차트 이동으로 정식 차트 전환 |
확인(화면) / 전환 시점 추정 |
A2 차트 초안, A4 내원이력 |
| WorkTask/HospitalTask(병원 업무) |
date, body, authorId, editorIds[], done, highlighted — 홈·플래너 좌측 공용 |
확인 |
A4 ②-4, A3 |
ReservationStatus 상태 머신(2025 플래너 기준) [A3 플래너, A6 S20, A2 네이버 — 확인 / 전이 조건 일부 추정]
stateDiagram-v2
[*] --> 요청 : 외부 채널 유입(네이버·구글·여신)
[*] --> 확정 : 내부 등록(데스크·코디)
요청 --> 확정 : 확정(수동 / 상품별 자동확정)
요청 --> 거절 : 거절(모두 거절·개별)
확정 --> 접수 : 내원 접수(태블릿·데스크)
확정 --> 취소 : 예약취소(사유) / 노쇼
요청 --> 취소 : 외부 취소 동기화(추정)
접수 --> 완료 : 진료·수납 종료(추정: 내원 완료)
취소 --> 확정 : 복구(미확인)
확정 --> 삭제 : 플랜 삭제(권한 '플랜 삭제')
완료 --> [*]
거절 --> [*]
- v2.4 목록 탭은
예약 / 접수 / 예약취소(+전체)뿐이었다 [V5 R10]. 2024-10 초기 카드 접두어는 대기 · 방문 · 취소 · 요청 · 업무였다가 2025-02부터 요청 · 확정 · 접수 · 완료 · 취소로 정리됐다 [A2, A4].
노쇼는 독립 상태가 아니라 **취소 + 사유 칩(취소:노쇼)**으로 표현된다 [A2 — 확인]. 지각은 색 규칙 트리거로만 보인다 [A4].
삭제는 취소와 구분되는 영구 삭제(VOC "예약 영구 삭제")이며 로그에 남는다 [A2].
4-3 외부 예약 채널
| 엔티티 |
필드 |
확신도 |
출처 |
| PartnerIntegration |
partner(naver · google · yeoshin), status(미사용·사용중), apiKey, keyIssuedAt, scheduleMapping(연동스케줄) |
확인(화면) / 매핑 의미 추정 |
A3 파트너사 |
| NaverAccount |
serviceId, naverId, 스마트플레이스 이동 |
확인 |
A4 네이버 |
| NaverProduct(예약상품, 구 비즈아이템) |
id, name, categoryId?(없으면 "플래너와 연동하려면 카테고리를 선택하세요."), autoConfirm |
확인 |
A4 네이버 |
| ExternalBooking |
partner, externalId, status(요청·확정·완료·거절/취소), product, category, bookerName, phone, bookedAt(KST 변환 — 구글은 국가별 타임존 자동 변환), requestedAt, requestNote, patientId?, planId? |
확인 |
A3, A4 |
| PartnerBillingEvent |
partner=google, bookingRequestId, fee=10,000(VAT 별도), month, cap 100,000 |
확인(요금) / 엔티티 추정 |
A3 구글 |
5. 접수·내원·대기열
5-1 Visit(접수 = 내원)
| 필드 |
설명 |
확신도 |
출처 |
| id / receptionNo(접수번호) |
통계·청구의 원천 연결키 |
확인 |
V4, V8 R5 |
| patientId |
|
|
|
| careType |
외래 · 입원 · 낮병동(2024-06 입원 토글 → 2025 세그먼트) |
확인 |
A3 접수 모달, A2 |
| receivedAt |
기본 현재 시각, ✎ 수정 가능 — 나이·자격조회 판정 기준 시점 |
확인 |
A1, A2 청구 |
| claimType |
공단청구(기본) · 비청구 · 자보청구. 접수 후 변경 가능. (A5는 보건소·산재 경로도 제안) |
확인 |
V1 R3, A1 |
| insuranceType(자격구분) |
건강보험 · 의료급여1종 … · 자동차보험 |
확인 |
V4, V9, A2 |
| visitPurposeId, subPurposeIds[] |
방문목적(필수, v2.4는 필수 아님으로 보이기도) + 세부목적(다중) |
확인 |
A1(방문목적*), V1 |
| doctorId |
필수. 구환은 직전 담당의 기본값 |
확인 |
V1 R6 |
| staffAssignments[] |
역할별 담당 칩 상담/이름 관리/이름 간호/이름 코디/이름 |
확인 |
A2 차트 초안, A3 통합뷰 |
| inflowTag |
이벤트/강남언니 같은 유입 채널 태그 |
확인 |
A4, A2 |
| questionnaireId? |
접수 시 문진 지정(2023-06~) |
확인 |
A1 |
| chartTemplateId? |
접수 시 차트템플릿 ▾ → 템플릿 적용 차트 자동 생성 |
확인 |
A1 |
| receptionTags[] |
접수태그(자유) |
확인 |
A3 |
| isEmergency, isPregnant |
☐응급 ☐임신부. 임신부는 여성에게만 표시 |
확인 |
V1 R9, A3 |
| receptionMemo |
접수메모(100자 이내) |
확인 |
A2 |
| chartMemo |
차트메모(차트구성 섹션) |
확인(섹션명) |
A4 차트구성 |
| visitKind(초진/재진) |
내원이력 태그·명세서 분류의 원천 |
확인 |
V8 R15, A4 |
| hasRemainingRx |
내원이력 잔여처방 태그(빨간 아이콘) |
확인(태그) / 의미 추정 |
A4 내원이력 |
| channel |
태블릿 · 데스크 · 예약 |
추정 |
V9 추정 엔티티 |
| medicalAidApprovalNo |
의료급여 진료확인번호 |
확인 |
A2, V9 |
| durStatus |
차트 헤더 DUR 점검(미점검) → DUR 통과 |
확인 |
V3 F4 |
| isCompleted / completedAt |
내원이력 날짜 옆 ✓ |
추정 |
V9 |
| isDraft |
내원이력 초안 |
확인(배지) |
A4 |
5-2 QueueEntry(위치 × 상태)
| 필드 |
설명 |
확신도 |
출처 |
| visitId, roomId |
현재 위치 |
확인 |
V1, V2 |
| status |
아래 열거 |
확인 |
V9 |
| order / sortIndex |
기본 접수 순. 보내기 시 대상 룸 맨 뒤. 2025 드래그로 변경 |
확인 |
V2 R2, A3 |
| statusChangedAt |
통합뷰 ⏰ 1시간 30분 전 |
확인 |
A3 |
| enteredAt, startedAt(진행중 경과 ⏱), completedAt |
|
확인(표시) |
A3 |
| VisitTransition 로그 |
from/to room, from/to status, at, by — 되돌리기 가능 |
추정(로그) / 되돌리기 확인 |
A1, V3 R17 |
QueueStatus(배지 색) [V1 R15, V9, A2, A3 — 확인]
| 값 |
색 |
의미 |
접수신청 |
빨강 외곽선 |
태블릿·앱 셀프 접수, 원무 확인 전 |
대기 |
주황 |
해당 룸 대기 |
우선대기 |
초록 |
먼저 부를 대상(정렬 반영 여부 미확인) |
진행중 |
파랑 |
진료·처리 중(경과시간 표시) |
완료 |
— |
통합뷰 완료 시각(2025) |
Visit/Queue 상태 머신 [A1 동선, V3 R17, V9, A3 — 확인, 보류는 우리 초안에만 있음]
stateDiagram-v2
[*] --> 접수신청 : 태블릿·앱 셀프 접수(룸=태블릿접수)
[*] --> 대기 : 데스크 접수(첫 상태 선택, 기본 대기)
[*] --> 우선대기 : 데스크 접수(첫 상태=우선대기)
접수신청 --> 대기 : 원무 확인·룸 배정
대기 --> 우선대기 : 우선대기 지정
우선대기 --> 대기
대기 --> 진행중 : 진행하기 / 행 클릭
우선대기 --> 진행중
진행중 --> 대기 : 보내기(다른 룸, 맨 뒤)
대기 --> 대기 : 보내기(룸 이동)
진행중 --> 완료 : 병원에서 내보내기(귀가)
대기 --> 완료 : 병원에서 내보내기
완료 --> [*]
- 보내기 = (다음 위치, 상태)를 한 번에 바꾼다. 현재 위치와 같은 목적지는 비활성 [V3 S5, V9 — 확인].
- 대기 보드
대기 N = 필터로 고른 룸들의 인원 합(진행중·우선대기 포함) [V1 R14].
- 초기 접수 상태를 사람이 고른다:
대기열* [진료실1▾][대기▾] [V1 R8].
5-3 ReceptionRequest(접수신청) / SelfCheckIn
| 필드 |
설명 |
확신도 |
출처 |
| deviceId |
태블릿 |
추정 |
A1 |
| method |
QR(2022) · PHONE · RRN |
확인 |
A1 태블릿, A6 S29 |
| matchedPlanId? |
휴대폰번호로 예약 매칭 → "해당 예약정보가 맞으신가요?" |
확인 |
A6 S29, A1 |
| patientId? |
구환 매칭, 신환은 주민번호 경로 |
확인(경로) / 신환 등록 단계 미확인 |
A6 |
| visitPurpose |
내원목적 |
확인 |
V9 F2, A3 |
| consents[] |
필수·선택(마케팅·AI 녹취) — 선택 항목은 미리 체크하지 않음 |
확인(2026) |
A3 |
| status |
접수신청 → (원무 확인) 대기 / 거부(제가 예약한 내용이 아니에요) / 접수 취소 |
확인(버튼) / 전이 추정 |
A1, A6 |
6. 차트
| 엔티티 |
필드 |
확신도 |
출처 |
| ChartSection(역할별 기록 칸) |
visitId, section(consult 상담 · care 관리 · caution 특이사항 · clinical 진료기록 · nursing 간호기록 · receptionMemo · chartMemo), body(서식 텍스트, 줄 색), authorId, updatedAt. 저장 버튼 없이 즉시 반영 |
확인 |
A4 역할별, V1 R21 |
| ChartLayout(차트구성) |
scope(user? role? dept?), sections[] — 13종: 접수메모·차트메모·파일·진료기록·이미지·진단 및 처방·간호기록·액션·수납·문서발급·오더세트/차트템플릿·쿠폰·포인트 (+2025 할 일·티켓) |
확인(항목) / 범위 미확인 |
A4, V2 R24 |
| Diagnosis |
visitId, kcdCode(점 없는 대문자), name, nameEn, isPrimary(주 — 첫 줄 자동), isSuspected(임상적 추정/최종), order, onsetDate(서류용) |
확인 |
V3 R2, A1 문서 |
| OrderLine(진단 및 처방 줄) |
visitId, kind(아래), code, name/displayName, dose·timesPerDay·days(약 3칸, 기본 1 1 1), usage, count(수가·검사), coverage(급여·비급여, 비급여(과세)/(면세)), dispense(원내·원외), copayType(본인부담률), unitPrice, amount, surchargeLabel(영상의학과전문의판독), specialNotes[](JS010·JT014 …), pacsLinked, autoRule(스마트진찰료·스마트관리료, 연령 가산 문구), source(검색·오더세트·단축어·티켓), ticketRef, performerId |
확인 |
V3, V7 R11, V9, A5 E-27 |
| Task(할 일) |
patientId, visitId, orderLineId?, memo, assigneeIds, status(대기 ○ · 진행중 ◐ · 완료 ✔), startedAt, completedAt, duration, plannedStart/End?, source(manual · auto_order) |
확인(2025-08) |
A3 할 일 |
| VisitImage |
patientId, visitId, source(PC 업로드 · 웹캠 촬영 · 모바일 · 장비 DSLR/ENT), takenAt, uploaderId, fileRef, thumbRef — 내원당 30장 |
확인 |
V1 R18, A4, A3 |
| Canvas(펜차트) |
태블릿 펜 기록 |
확인(기능) / 필드 미확인 |
A1, A4 |
| Recording / Timer |
visitId, fileUrl, duration / startedAt, endedAt(2025-02) |
확인(업데이트 노트) |
A4 |
| LabResult |
visitId, labGroup(원내검사실 · 수탁기관), itemName, value, judgement, reference, reportedAt, readingUrl(PACS 판독소견), status |
확인 |
V2 R22 |
| QuestionnaireResponse |
templateId, patientId, visitId?(본 진료건), submittedAt, answers[], editedBy/At(답변 편집 가능), 미응답 (무응답) |
확인 |
A1 문진 |
| Routine |
name(진료완료 · 일괄진료 · 문서완료 · DUR), steps[](DUR 점검 → 관리료 재산정 → 약 조제 전송 → 전자서명 …) — 순차 실행, 단계 상태 대기→진행→완료, 취소 가능 |
확인 |
A6 S12 |
OrderLine.kind(행 아이콘으로 구분) [V9, V3, A3 — 확인]: 진찰료/관리료(수가) · 약 · 주사 · 처치/행위 · 검사(영상·검체) · 치료재료 · 문서 · 예방접종 · 코드 오더(MS002 원내투약 주사제) · 지시·메모(가루약 처방) · 티켓 구매 / 티켓 사용.
Task 상태 머신 [A3 — 확인]
stateDiagram-v2
[*] --> 대기 : 수동 등록 / 오더 추가 시 자동 등록(설정 ON)
대기 --> 진행중 : 시작(경과시간 표시)
진행중 --> 완료 : 완료(소요시간·완료시각 기록, 취소선)
대기 --> 완료
대기 --> [*] : 삭제
7. 라이브러리(마스터)
| 엔티티 |
필드 |
확신도 |
출처 |
| ClaimMasterItem(EDI아이템, 벤더 공용·읽기 전용) |
claimCode, nameKo/En, itemClass(대/소), detailCode(주성분코드), price(고시가), manufacturer, kind, effectiveFrom/To, allowedSpecialNoteCodes[] |
확인 |
V7 R2 |
| UserItem(사용자아이템, 병원별) |
category(수가·약가·치료재료대), itemClass(대/소, 필수), claimCode(필수, 자유 문자열 — EDI 코드와 겹칠 수 있음), nameKo(필수), nameEn, mainIngredientCode, manufacturer, nonCoveredPrice(필수, 기본 0). category·itemClass·claimCode는 생성 후 불변 |
확인 |
V7 R3~R5 |
| DocumentItem(문서아이템, 16종 카탈로그) |
nameKo, itemClass(진찰료/응급 및 회송료), templateRef |
확인 |
V7 R7 |
| VaccinationItem |
탭만 확인 |
미확인 |
V7 |
| OrderSetFolder / OrderSet / OrderSetLine |
폴더(1단, 번호 접두 정렬) > 세트 > 줄. 줄 = lineType(상병·약·수가·영상·문서·검사), ref, displayName, isPrimaryDx, dose/dailyFreq/days/usage/dispensing, count, copayType, unitPrice(급여면 고시가 잠금), pacsLinked, specialNotes[]. 파생 totalUnitPrice = Σ unitPrice(수량 곱 없음). 공용 세트(붉은 십자, 시스템 배포) |
확인 |
V7 R8~R13, V3 |
| Shortcut(단축어) |
keyword(한글·영숫자), orderSetLineId(1:1) — 차트 / 호출 |
확인 |
V7 R15 |
| QuickOrder |
검색 탭 ⚡퀵오더 |
미확인 |
V3 |
| ChartTemplate |
folder > template, 진료기록 본문 + 처방 줄. 차트 칩(SOAP·외래기록지·소아기록지), 접수 시 지정 |
확인 |
A1, V9 |
| Phrase(자주 쓰는 문구) |
label(칩), body, color?, owner(개인/병원 — 미확인). 진료기록 하단 칩·/ |
확인 |
V1, A6 |
| TicketProduct |
code(TKnnnn), name, kind(single N회권 · choice_single 주차별 · choice_multi 옵션 풀), totalCount, price, taxType(비급여 과세), rounds[]{roundNo, options[]}, validityDays?(만료일 없음 가능) |
확인(유형·칩) / 등록 화면 미공개 |
A3 티켓 |
| CouponTemplate |
name(첫 방문 이벤트 · 주름 보톡스 1+1 · VIP 전용 · 지인 할인 10% · 생일쿠폰), method(비율 · 정액 추정), value, active. 유효기간·대상·중복 규칙 미공개 |
확인(이름·비율) / 나머지 미확인 |
A3, A4 |
| Questionnaire(문진) |
name, items[{type(single·multi·scale 1~10·text), required, options}] — 라이브러리 > 문진 |
확인 |
A4 문진, A6 |
| MessageTemplate |
folderId, name, channel(문자 SMS/LMS/MMS · 친구톡 · 알림톡), purpose(알림성 · 광고성 → 본문 앞 (광고)), title, body(예약어), images[≤3], surveyLinkId?, allowFallback(대체발송 허용), isSystem(알림톡 기본 템플릿 읽기 전용) |
확인 |
A4 템플릿, V6 |
| ConsultTemplate(메디톡 상담 매크로) |
title(해시태그형), bodies{ko, zh, ja, en} |
확인 |
A3 |
8. 수납·원무
8-1 진료비·수납
| 엔티티 |
필드 |
확신도 |
출처 |
| Charge(진료비 산정, 내원당 1) |
totalFee(진료비총액), insurerShare(공단부담금), copay(본인부담금), nonCovered(비급여), patientTotal(환자부담 총액 = 본인+비급여), autoInsuranceClaim(자보청구금), subsidy(지원금), discount(할인금), amountDue(받을 금액), roundingAdjustment(끝수처리 조정액) — 오더 입력 즉시 재계산 |
확인 |
V3 R8~R10, V4 |
| Payment(수납 행) |
visitId, paidAt(MM.DD), method(카드 · 현금 · 할인금 · 선납금 · (2025) 포인트·쿠폰), amount, installment(카드 필수: 일시불/개월), cashReceipt(bool), bankTransfer(bool), idNumber(신분확인번호), approvalNo, terminalTxId?, kind(수납/환불) |
확인 |
V3 S10, V9 |
| Refund |
paymentId?, amount, refundedAt, method — 수납 패널 ▸ 환불 접힘 섹션 |
확인(섹션) / 입력 UI 미확인 |
A2, V4 |
| Receivable(파생) |
남은 금액 = 받을 금액 − Σ수납 (+ Σ환불) |
확인(− 수납) / 환불 반영 추정 |
V2 R17, A2 |
| DailySettlementReport |
date, 카드 승인·취소(건수·금액), 카드사별, 현금영수증 승인·취소 — 알림톡 발송(VAN사 부가서비스 추정) |
확인(메시지) |
A2 |
수납(내원 단위) 상태 — 닥터팔레트는 명시 상태 배지를 보여주지 않고 남은 금액으로 판단한다(추정 상태 머신).
stateDiagram-v2
[*] --> 미수납 : 오더 발생(받을 금액>0)
미수납 --> 부분수납 : 수납 추가(합계 < 받을 금액)
부분수납 --> 완납 : 남은 금액 = 0 (+수납 추가 버튼 숨김)
미수납 --> 완납
완납 --> 부분수납 : 오더 추가로 받을 금액 증가 / 환불
부분수납 --> 미수 : 귀가(내보내기) 후에도 잔액 > 0 → 미수 목록
미수 --> 완납 : 나중 날짜 수납(통계는 수납일 기준)
8-2 쿠폰·포인트·선납금 (2025)
| 엔티티 |
필드 |
확신도 |
출처 |
| CouponApplication |
visitId, templateId?(없으면 직접입력), method(비율·정액), rate, targetOrderLineIds[](처방 줄에 걸림), baseAmount, discountAmount, appliedBy, appliedAt |
확인 |
A3 쿠폰 |
| PointLedger |
patientId, type(use · charge · refund, + earn/expire 추정), points, paidAmount?(충전 결제액), bonusPoints?(예 100,000원 → 110,000P), visitId?, by, at, balance |
확인(사용·충전·환불 탭) |
A3 포인트 |
| PrepaidLedger(선납금) |
patientId, 구분(입금/출금), amount, balance — 결제수단 선납금으로 차감 |
확인(잔액·수단) / 충전 UI 미확인 |
V4, A2 |
8-3 티켓(회차권)
| 엔티티 |
필드 |
확신도 |
출처 |
| PatientTicket |
id, patientId, productId, purchaseVisitId(구매 오더 줄 TK1581 10회권 구매 … 비급여(과세) 350,000원), purchasedAt, price, couponDiscount, netPrice(패키지 가격), usedCount, totalCount, expiresAt?(만료일 없음 가능), status(사용중 · 완료 · 환불 — 탭 `사용 |
완료`) |
확인 |
| TicketUsage |
ticketId, visitId, roundNo, optionId?(선택형), orderLineId(TK… 사용 금액 없는 줄), usedAt, by |
확인 |
A3 |
| TicketExtension |
ticketId, oldExpiry, newExpiry, by, at(기간 연장) |
확인(버튼) / 필드 추정 |
A3 |
| TicketRefund |
ticketId, usedCount, remainingCount, netPrice, refundAmount(직원 직접 입력), by, at |
확인 |
A3 |
| RevenueRecognition |
ticketUsageId, recognizedAmount, recognizedAt — 사용 시점 매출, 미사용분 = 선수금 |
확인(주장) / 계산식 미공개 |
A3 news#166081947 |
PatientTicket 상태 머신 [A3 — 확인(탭·버튼) / 만료 처리 미확인]
stateDiagram-v2
[*] --> 사용중 : 구매 오더 수납
사용중 --> 사용중 : 칩 클릭(사용 n/N) · 기간 연장
사용중 --> 완료 : usedCount = totalCount
사용중 --> 환불 : 우클릭 '티켓 환불'(금액 수동)
사용중 --> 만료 : expiresAt 경과(처리 방식 미확인)
완료 --> [*]
9. 문서·전자서명
| 엔티티 |
필드 |
확신도 |
출처 |
| IssuedDocument |
visitId, docType(처방전 약국/환자보관용 · 진단서 · 건강진단서 · 상해진단서 · 진료기록지 · 진료비계산서영수증 · 진료비세부내역서 · 건강검진증명서 · 진료확인서 …), status(미발급 → 발급완료), serialNo(연번호 No. = 발급시각 YYYYMMDDHHmm 접두 + 일련), applicant(신청인, 기본 환자), relation(환자와의 관계, 기본 본인), note(비고), formInputs{용도, 발병일, 소견, 입·퇴원일}, issuedAt, issuedBy, printLog |
확인 |
V3 R13~R16 |
| ConsentForm(태블릿 동의서) |
서식, 환자 스냅샷, 진단명, 시술일자, 서명, status(임시저장 · 완료) |
확인(화면 일부) |
A6 S19 |
| PatientAppDocRequest |
userId, hospitalId, docType, requestedAt, status(요청 → 발급, 약 5분 비동기), issuedAt |
확인 |
V9 F7 |
| LabelPrint / NemonicPrintJob |
patientId, visitId, sections[상담, 진단 및 처방], printedAt |
확인(출력 레이아웃) |
A2 네모닉, A4 ⋮ |
IssuedDocument 상태: (오더·자동 생성) 미발급 → 발급(번호 부여·확정) → 출력(인쇄/PDF, 반복 가능). 전체 발급 후 헤더 버튼이 전체 출력으로 바뀐다 → 발급과 출력은 별개 [V3 R13 — 확인(버튼) / 분리 해석 추정].
10. CRM·메시지
| 엔티티 |
필드 |
확신도 |
출처 |
| NotificationSetting(v2.4 알림 메시지) |
trigger(RECEPTION_GUIDE · RESV_CREATED · RESV_CHANGED · RESV_CANCELLED · RESV_REMINDER), enabled(기본 OFF), showQueueNumber, includeQuestionnaireLink(예약 변경), sameDayEnabled + sameDayTime(오전 8/9시 예시), daysBeforeEnabled + daysBefore(1~5) |
확인 |
V6, A1, A6 S23 |
| AutoMessageRule(2025 자동발송 메시지) |
name, active, messageType(알림성·광고성), trigger(예약 변경 · 예약 완료 · 예약 취소 · 예약 내원일 · 접수), categoryIds[](카테고리별 다른 메시지), templateId, leadTime? |
확인 |
A4 자동발송 |
| CrmRule(2024 조건 기반) |
trigger(QUESTIONNAIRE · BIRTHDAY · PRESCRIPTION_ELAPSED(처방 후 N일, 예 보톡스 3개월) · SCHEDULE_RESERVATION(특정 스케줄 예약자만)), filters{orderCodes[], delayDays, scheduleIds[]}, templateBody, channel, sendTime, active |
확인(4종 원문) |
A2 CRM |
| MessageDispatch(발송 1건) |
id, type, sourceRef(reservationId / receptionId / ruleId), recipientName, recipientPhone(마스킹 표시), channel(ALIMTALK · SMS · LMS · MMS · 친구톡), status(발송 중 · 발송성공 · 발송실패), requestedAt, sentAt, unitPrice, fallbackOf? |
확인 |
V6, A1 |
| MessagingBillingMonth |
yearMonth, totalExVat, totalIncVat, 채널별 금액·건수, sentCount(=성공), successCount, failCount |
확인(검산 일치) |
V6 요금 검산 |
| MessagePrice |
channel, unitPrice(알림톡 20 · SMS 25 · LMS 50), vatRate 10% |
확인 |
V6 S11 |
| CreditWallet / TopUp |
balance, bonus_balance / amount, bonus_rate(10~60%) — 2023-11 선불 충전 도입(후불 병행) |
확인(보너스 표) / 소진 순서 미확인 |
A5 |
| PatientGroup / Campaign |
name, rule 또는 members[] / groupId, templateId, sentAt, stats |
확인(사례) / 그룹 방식 미확인 |
A4 그룹 발송 |
| Conversation / Message(메디톡 플러스) |
channel(LINE · INSTAGRAM · WECHAT · WHATSAPP), externalUserId, patientId?(미등록환자), status(신규 · 상담중 · 보류 · 완료), assigneeId, tags[], inflow, memo, autoTranslate / direction, originalText, originalLang, translatedText, targetLang |
확인(2025-12) |
A3 메디톡 |
| SurveyQuestion / SurveyDispatch / SurveyResponse(만족도) |
type(staff · general), deptId, linkProcedures, scale / patientId, visitId / score 1~5, comment, staffId |
확인 |
A3 만족도 |
MessageDispatch 상태 머신 [V6·A1 — 확인(3색 배지) / 대체발송 판정 추정]
stateDiagram-v2
[*] --> 예약됨 : 트리거 발생(즉시) / 리마인더 시각 도래 대기
예약됨 --> 발송중 : 발송 시각
발송중 --> 발송성공 : 알림톡 성공(과금)
발송중 --> 발송실패 : 실패(과금 제외)
발송실패 --> 대체발송 : 카카오 미사용·실패 → SMS/LMS(fallbackOf)
대체발송 --> 발송성공
예약됨 --> 취소 : 예약 취소·CRM 제외 체크(추정)
11. 청구(보험)
| 엔티티 |
필드 |
확신도 |
출처 |
| ClaimBatch(원청구서) |
unit(월청구 · 주청구), year, month, insuranceType(필수, 기본 건강보험), status, claimNo?(발급 시 10자리, 앞 6자리 진료연월), statementCount, totalMedicalFee, totalClaimAmount, eligibilityErrorCount, fileName({claimNo}.ghp), createdAt, issuedAt |
확인 |
V8 |
| ClaimStatement(명세서 = 환자 × 내원일) |
batchId, serialNo(명일련번호 5자리), patientId, visitDate, receptionNo, doctorId, totalFee, copay, claimAmount, excluded(+at/by), issues[] |
확인 |
V8 R5 |
| StatementIssue |
code(상병 미기재 · 주상병 미기재 …), message, deepLink(차트열기) |
확인 |
V8 |
| EligibilityIssue |
헤더 보험자격 오류 N건 — 발급을 막지 않음 |
확인(건수) / 상세 미확인 |
V8 |
| ChartReviewFinding(심사점검) |
visitId, category(상병점검 · 특정내역 · 중복 · 누락), targetOrderId, criteria{심사번호, 보험인정기준 원문}, recommendedDiagnoses[] |
확인 |
V8 흐름 A |
A5는 여기에 코드 기간 버전·규칙 엔진·명세서 상세(E-01~E-38)를 제안한다 — 우리 P3 범위다.
ClaimBatch 상태 머신 [V8 — 확인]
stateDiagram-v2
[*] --> 생성중 : 원청구서 생성(비동기 수집)
생성중 --> 작성중 : 수집 완료(건수·금액 채움)
작성중 --> 작성중 : 제외(즉시 반영) · ↻ 재생성·재집계
작성중 --> 발급완료 : 발급하기(확인창 없음, 청구번호·.ghp)
발급완료 --> 발급완료 : 내려받기(재다운로드)
작성중 --> [*] : 원청구서 삭제
발급완료 --> [*] : 원청구서 삭제(발급 후에도 가능)
12. 통계·경영(저장 모델 관찰)
| 엔티티 |
필드 |
확신도 |
출처 |
| MonthlyReport |
hospitalId, period, kpis, narrative[], charts[] — 월초 홈 봉투 카드 |
확인(화면) / 스냅샷 저장 추정 |
V4, V9 |
| InsightWidget / Layout |
ownerId?, type, unit, position, visible — 배치바꾸기·✕ |
확인 |
V4 |
| WaitlistViewConfig |
mode(기본 · 확장형), lists{대기 · 예약 · 방문 · 통합}, visibleFields[] |
확인 / 저장 범위 미확인 |
A3 |
통계 기준일(추정, V4 §8): 매출 = 진료일, 수납 = 수납일, 미수 = 진료일. 객단가 = 매출 ÷ 진료횟수(접수 건).
13. 우리 설계 초안(docs/design/domain-model.md v0.1)과의 차이·누락
판정: 반영됨 = 초안이 이미 담음 / 차이 = 초안과 관찰이 다름(결정 필요) / 누락 = 초안에 없음. 우선순위는 mvp-scope.md 기준(P1 MVP · P2 · P3).
"권고"는 구현 직전 확정안 제안이다. 초안은 수정하지 않았다(읽기 전용).
13-1 차이 — 모델 형태가 다른 것 (결정 필요)
| # |
주제 |
닥터팔레트(as-is) |
초안 v0.1 |
권고 |
우선 |
| D-01 |
예약 시간 모델 |
2024-10에 슬롯 모델(v2.4)을 버리고 자유 시작~종료 + 카테고리 컬럼으로 전환. 슬롯·정원 개념은 플래너 화면에 없음 |
Schedule+SchedulePeriod(slotMinutes·slotCapacity·weeklyHours) 슬롯 모델 + Reservation.startMinute/durationMinutes |
둘 다 수용: Reservation은 start/end(자유) 저장, 슬롯은 "제안 그리드·정원 경고"용 계산값으로만 사용. 운영시간·정원 없는 스케줄(카테고리형)도 허용(slotCapacity nullable) |
P1 |
| D-02 |
예약 상태 |
요청 · 확정 · 접수 · 완료 · 취소 · 거절 · 삭제(+노쇼는 취소 사유 칩) |
reserved, confirmed, checkedIn, completed, cancelled, noShow |
requested, rejected 추가(외부 채널 P3이나 상태는 P1에 예약). noShow는 독립 상태로 유지하되 통계 호환 위해 cancelReason과 별도로 둔다. reserved vs confirmed 중복 여부 결정 — 권고: 내부 등록은 곧바로 confirmed, reserved 제거 |
P1 |
| D-03 |
예약 자원 축 |
열 = 카테고리(시술·장비·의사), 담당의·담당자는 별도 필드. A6은 "열=스케줄, 색=카테고리" 가능성도 제기 |
Schedule(kind: doctor·procedure·equipment·counseling) 하나로 자원·색 겸함 |
Schedule 유지하되 Reservation.doctorMemberId?, staffMemberId?(담당자) 추가 — 열과 담당을 분리 |
P1 |
| D-04 |
게스트(신환) 예약 |
환자 레코드 없이 게스트 필드. 2025엔 임시환자(isTemporary)도 있음 |
guest 필드 방식 |
게스트 방식 유지 + Patient.isGuest(초안에 있음)를 "임시환자"로 명확히 정의. 둘 중 하나로 통일 권고: 예약은 guest 필드, 태블릿·외부 유입은 임시환자 |
P1 |
| D-05 |
대기 상태값 |
접수신청 · 대기 · 우선대기 · 진행중 · (완료). 보류 없음 |
requested, waiting, priority, inProgress, hold, done |
hold는 관찰 근거 없음 → 유지 여부 결정(권고: 제거하거나 P2). requested는 ReceptionRequest와 중복 — 접수신청을 QueueEntry 상태로 둘지 별도 수신함으로 둘지 하나로 |
P1 |
| D-06 |
Visit 상태·종료 |
병원에서 내보내기가 명시적 종료 동작. 수납 완료와 무관하게 내보낼 수 있고 잔액은 미수로 남음 |
규칙 "수납 완료 + 마지막 룸 종료 → completed" |
명시적 내보내기를 종료 트리거로 채택. 수납 완료는 조건이 아니라 경고(잔액 있으면 "미수로 남습니다" 확인) |
P1 |
| D-07 |
청구유형 |
공단청구(기본) · 비청구 · 자보청구. 산재는 관찰 안 됨 |
ClaimType { uninsured, nhis, autoInsurance, industrial }, MVP 기본 uninsured(mvp-scope) |
값 집합은 유지. 기본값은 우리 타깃(비급여 의원)에 맞게 uninsured 유지 — 닥터팔레트와 의도적 차이로 문서화 |
P1 |
| D-08 |
결제수단 |
카드 · 현금 · 할인금 · 선납금(v2.4) — 할인금이 결제수단. 2025엔 포인트·쿠폰이 결제 전 차감 |
PayMethod { card, cash, transfer, prepaid, other } + 할인은 InvoiceAdjustment |
초안 방식(할인=조정)이 회계상 옳음 → 유지. 단 현금의 하위 속성 bankTransfer(계좌이체)와 cashReceipt*를 초안처럼 분리 유지, UI는 닥터팔레트처럼 "수납 추가" 한 모달에서 처리 |
P1 |
| D-09 |
수납 엔티티 경계 |
내원당 Charge 1개(발생금액) + 수납 행. Invoice 개념 없음. 회차권 판매도 오더 줄(구매) |
Invoice(내원 없이도 가능) + InvoiceLine(kind: order·ticketSale·prepaidCharge) |
초안 유지(내원 없는 선납금 충전·티켓 판매 수용). 단 티켓 구매를 OrderLine 종류로도 입력할 수 있게(OrderKind.ticketPurchase) 하여 차트 흐름과 일치 |
P1 |
| D-10 |
쿠폰 적용 단위 |
쿠폰은 특정 처방 줄(targetOrderLineIds)에 걸림. 템플릿 없이 직접입력(할인율+처방 선택) 가능 |
PatientCoupon(발급형) + InvoiceAdjustment(kind: coupon) |
발급형은 유지하되 즉석 적용(직접입력) 경로와 adjustment.targetLineIds[] 추가. 닥터팔레트에는 "발급" 단계가 보이지 않음(선택만) — 발급형은 P2로 미뤄도 됨 |
P1 |
| D-11 |
포인트 충전 |
충전 = 결제액 + 보너스 포인트(100,000원 → 110,000P). 선납금과 별도 원장 |
PointLedger(reason: earn·use·bonus·expire·refund·adjust), PrepaidLedger 분리 |
반영됨. PointLedger에 paidAmount(충전 결제액) 필드 추가 필요 |
P1 |
| D-12 |
티켓 선택형 |
single · choice_single(주차별 구성) · choice_multi(옵션 풀, 쓴 옵션 사용불가) |
TicketKind{count, amount, period}, TicketSelection{fixed, choiceSingle, choiceMulti} |
반영됨(선택 모드). choice_single은 회차별 구성(rounds[])이 필요 — TicketProduct.rounds: List<{roundNo, feeItemIds[]}> 추가. amount/period권은 관찰 근거 없음(P2) |
P1 |
| D-13 |
티켓 매출 인식 식 |
"사용한 만큼만 매출" 주장, 계산식 미공개 |
recognizedAmount = 가격 ÷ 총회차 × count |
초안 식 채택, netPrice(쿠폰 할인 후) 기준으로 명시. 마지막 회차는 잔액 보정(끝전) 규칙 추가 |
P1 |
| D-14 |
차트 기록 칸 |
상담 · 관리 · 특이사항 · 진료기록 · 간호기록 + 접수메모 · 차트메모 |
NoteKind{clinical, counseling, care, nursing, procedure}, 특이사항은 Patient.specialNote |
procedure(시술기록)은 관찰 없음(진료기록에 씀) — 유지 여부 결정. receptionMemo는 Visit에 있음(반영), chartMemo 누락 |
P1 |
| D-15 |
오더 줄 필드 |
copayType(본인부담률), specialNotes, pacsLinked, surchargeLabel, autoRule, source, displayName |
kind·coverage·dispense·dose… |
P1은 displayName, source(검색·세트·단축어·티켓) 추가. 나머지는 P3 |
P1/P3 |
| D-16 |
문서 번호 |
발급시각 YYYYMMDDHHmm + 일련 |
serialNo |
형식 규칙을 06 문서 BR로 확정. 발급(번호)과 출력(인쇄 횟수) 분리 — 초안 printCount 반영됨 |
P1 |
| D-17 |
알림 트리거 |
접수 안내 · 예약 완료/변경/취소 · 당일/사전 리마인드(+ 2024 생일·처방 경과·스케줄별·문진) |
MessageTrigger 6종 + questionnaireLink·manual |
반영됨. 2024 조건 규칙(birthday, prescriptionElapsed, 스케줄 필터)은 P2. MessageSetting에 scheduleIds/categoryIds 필터와 includeQuestionnaireLink 추가 |
P1/P2 |
| D-18 |
발송 상태 |
발송 중 · 성공 · 실패(+대체발송) |
queued, sent, failed, fallbackSent, cancelled |
반영됨. sending(발송 중) 추가 여부는 선택. 과금은 성공 건만(06 BR) |
P1 |
| D-19 |
권한 모델 |
역할(그룹) × 모듈 × 세부 동작 체크박스, 멤버는 직군·부서 |
Role.permissions: List<String> 키 집합 |
반영됨(키 = 모듈.동작). 관찰된 세부 동작 중 chart.delete, nursing.read/write, coupon.read/write, point.read/write, patientNote.editOthers, planner.category, plan.delete, stats.insight 키 추가 |
P1 |
13-2 누락 — 초안에 없는 엔티티·필드
| # |
누락 항목 |
닥터팔레트 근거 |
권고 |
우선 |
| M-01 |
Task(할 일) — 환자·내원·오더 연결, 수행자 다중, 대기→진행→완료, 소요시간 |
A3(news#167389387) |
mvp-scope P2 항목. 모델만 P1에 예약(ClinicTask와 별개) |
P2 |
| M-02 |
VisitStaffAssignment(역할별 담당: 상담·관리·간호·코디) |
A2 차트 초안, A3 통합뷰 |
Visit.counselorMemberId만 있음 → List<{role, memberId}>로 일반화. 만족도·담당자별 통계의 원천 |
P1 |
| M-03 |
Visit.inflowTag / acquisition 방문 단위 |
이벤트/강남언니 방문 태그 |
초안은 Patient.acquisitionChannelId(환자 단위)만 → 방문 단위 Visit.acquisitionChannelId? 추가 |
P1 |
| M-04 |
Visit.careType(외래·입원·낮병동) |
A3 접수 모달 |
enum만 두고 P1은 외래 고정 |
P3 |
| M-05 |
Visit.isEmergency, receptionTags[], chartTemplateId, questionnaireId |
A2·A3 접수 모달 |
isEmergency, chartTemplateId P1 추가, 나머지 P2 |
P1/P2 |
| M-06 |
IdentityVerification(본인확인, 6개월 유효) |
A2(2024-05 의무화) |
급여 진료 시 필수 → P3이지만 비급여도 신분 확인 기록 수요 있음. 모델 P3 |
P3 |
| M-07 |
EligibilityCheck(자격조회 스냅샷) |
V1 R2 |
P3(어댑터) |
P3 |
| M-08 |
PlanCategory / 업무 플랜(WorkBlock) |
A2 플래너 |
Schedule로 흡수하되 업무 블록(자리비움)용 Reservation.type = work 또는 StaffBlock 추가 |
P1 |
| M-09 |
ChartDraft(차트 초안) — 내원 전 상담·오더 사전 작성 |
A2 news#124177982 |
ChartNote/OrderLine이 visitId 필수라 초안 불가 → reservationId 기반 초안(또는 Visit.status = draft) 필요 |
P2 |
| M-10 |
PlanColorRule, Reservation.colorOverride는 있음 |
A4 |
색 자동 규칙은 P2 |
P2 |
| M-11 |
ExternalBooking / PartnerIntegration / 상품 매핑(autoConfirm) |
A3·A4 |
초안은 source·externalRef만 → P3에 엔티티 추가, P1은 샌드박스 어댑터용 ExternalBooking 최소형 |
P3 |
| M-12 |
ReceptionRequest.consents / matchedReservationId / method |
A1·A3·A6 |
초안 ReceptionRequest에 reservationId?, method(phone·rrn·qr), 동의 결과 연결 추가 |
P2 |
| M-13 |
ConsentRecord 필드: required, channel = staff_verbal_attest, attestedBy, AI 녹취 동의 종류, "비동의도 기록" |
A3 news#171946700 |
PatientConsent에 required, attestedById? 추가, ConsentKind에 aiRecording 추가 |
P1(필드)/P3(AI) |
| M-14 |
LabResult(검사결과) |
V2 R22 |
초안에 없음. 수탁·PACS 연동 전제 → P3 |
P3 |
| M-15 |
QuestionnaireResponse 편집 이력·본 진료건 연결 |
A1 |
초안 문진(P2)에 visitId, editedById 추가 |
P2 |
| M-16 |
Routine 실행 이력 |
A6 S12 |
초안 Routine(P2)은 정의만 → 실행 로그 필요 시 추가 |
P2 |
| M-17 |
WaitingScreen / Holiday 외 대기스크린 설정(요일 세트·마스킹·영상·음성호출) |
A6 S26~28 |
P2 |
P2 |
| M-18 |
Refund 링크: 원 결제 참조 |
V4, A2 |
Payment.originalPaymentId 반영됨 ✓ |
— |
| M-19 |
Charge의 지원금·자보청구금·끝수처리 조정 |
V3, V4 |
Invoice.roundingAdjustment는 조정 줄로 반영(P3). subsidyAmount P3 |
P3 |
| M-20 |
Payment.installmentMonths 필수(카드), idNumber(현금영수증 신분확인번호) |
V3 S10 |
installmentMonths 반영, cashReceiptNo는 신분확인번호 의미로 명시 |
P1 |
| M-21 |
MessageTemplate: folder, images[≤3], allowFallback, 광고 prefix |
A4 템플릿 |
폴더·이미지는 P2, allowFallback P1 |
P1/P2 |
| M-22 |
CreditWallet 보너스 잔액·충전 구간 |
A5 |
초안 MessageCredit(delta)만 → reason: bonus 추가(P2) |
P2 |
| M-23 |
PatientGroup(세그먼트) |
A4 |
Campaign.segment(JSON)로 반영됨(P2) ✓ |
— |
| M-24 |
HospitalInfo 서류용 직인·의사 인장/서명 이미지·면허번호 |
V3 R14, A1 |
Staff.licenseNo 있음. 직인·인장 이미지 경로 누락 → ClinicSetting.sealImagePath, Staff.signatureImagePath 추가 |
P1 |
| M-25 |
ChartLayout 저장 범위 |
A4 |
초안 ClinicSetting.chartPanelsByJob(직군별) → 관찰은 개인 설정 가능성 → MemberPreference(개인) + 직군 기본값 2단 |
P1 |
| M-26 |
WaitlistViewConfig(확장형·통합뷰·표시 항목) |
A3 |
개인 설정으로 MemberPreference에 포함 |
P2 |
| M-27 |
Department(부서) |
A3·A4 |
ClinicMember.jobType만 → department? 문자열 추가(만족도·권한 필터) |
P2 |
| M-28 |
환자 이름 60자·임시환자 |
A4 |
이름 길이 60 제약 명시, isGuest → 임시환자 의미 |
P1 |
| M-29 |
SecurityAdmin(IP 제한 예외) |
A4 |
IpAllowRule만 → "소유자·보안관리자는 IP 제한 예외" 규칙과 ClinicMember.isSecurityAdmin 추가 |
P1 |
| M-30 |
ClaimBatch / ClaimStatement / 심사점검 |
V8 |
초안 없음(P3). 06 BR과 A5 E-01~E-38 참조 |
P3 |
| M-31 |
Conversation(메디톡)·Survey(만족도) |
A3 |
초안 없음 — P3/P2 |
P2/P3 |
| M-32 |
Recording/Timer, Canvas, 장비 이미지 source |
A4 |
MediaSource{pc, mobile, device} 반영, webcam 추가 권고. 녹음은 P2 |
P2 |
13-3 초안에만 있는 것 (닥터팔레트에서 관찰 안 됨 — 유지 판단)
| 항목 |
판단 |
ReservationEvent.diff(JSON) |
닥터팔레트 최근 플랜은 액션만 보임. diff는 우리 강점(유지) |
QueueStatus.hold |
근거 없음 → 제거 또는 P2 |
NoteKind.procedure |
근거 없음 → 진료기록과 통합 검토 |
DailyClosing(일마감) |
닥터팔레트는 통계·알림톡 정산 리포트로 대체. 우리 P1 유지(원무 요구) |
TicketKind.amount/period |
관찰 없음 → P2 |
CouponPolicy.minAmount/maxDiscount/validDays |
닥터팔레트 미공개 → 우리 정책으로 유지(합리적 확장) |
ChartNote.version(낙관적 잠금) |
닥터팔레트는 동시 편집 방식 비공개. 유지 |
출처 파일
- 텍스트 분석:
A1_news_2022_2023.md(외래접수·환자기록·수납·CRM·동선·태블릿·구현 시사점), A2_news_2023_2024.md(본인확인·접수 모달·수납 패널·네이버·플래너·차트 초안·CRM 규칙·CID·권한), A3_news_2025_2026.md(접수 모달·쿠폰·포인트·티켓·플래너·파트너사·메디톡·만족도·통합뷰·할 일·녹취 동의), A4_customer_stories.md(①·②·모듈별·권한 매트릭스·IP 제한), A5_billing_rules_and_market.md(②·③·1-5·1-7·4-4), A6_feature_pages_ui.md(S12·S16·S19·S20·S23·S24·S26~S29)
- 영상 분석:
V1_reception_treatment.md, V2_chart.md, V3_dxrx_documents.md, V4_stats_insight.md, V5_reservation_crm_part1.md, V6_reservation_crm_part2.md, V7_library.md, V8_claims.md, V9_intro.md — 각 '도메인 규칙·데이터' 절
- 비교 대상:
docs/design/domain-model.md(v0.1), docs/product/mvp-scope.md