콘텐츠로 이동
상품 기준 데이터, 구매 문서, 예약 계획, 후보 시간, 확정 예약을 한 작업대에서 연결하는 작은 로봇 작업자들
상품을 구매한 사실과 특정 시간에 예약하기로 한 사실은 같은 데이터가 아닙니다. 그 사이의 업무 판단을 분리해야 합니다.

이벤트 상품은 “한 번 방문하는 상품”이라고 설명하기 쉽습니다. 하지만 예약 서비스가 처리해야 하는 일은 상품을 판매하는 일이 아니라, 그 구매가 어떤 진료 의무와 예약으로 이어지는지 재현하는 일입니다.

환자 A가 이벤트 상품을 구매했다고 해보겠습니다. A가 결제한 순간 병원 달력의 특정 시간과 의사가 자동으로 확정되는 것은 아닙니다. 먼저 상품 기준 데이터와 구매 기준 데이터를 확인하고, 예약 가능한 조건을 계산한 다음, 고객이 제안에 동의해야 비로소 확정 예약이 생깁니다.

구매 사실 ≠ 예약 가능 조건 ≠ 확정 예약

이번 글은 이벤트 상품의 최초 예약을 환자 A의 시간축으로 따라갑니다. N회 상품과 패키지 상품은 같은 경계가 왜 필요한지 보여 주는 비교로만 사용합니다. 반복 회차 전체 계산, 패키지 전환, 노쇼 페널티, VIP 우선 예약은 각자의 운영·상품 정책을 다루는 다음 범위로 남겨 둡니다.

이벤트 상품을 샀는데 왜 아직 예약이 아닌가

섹션 제목: “이벤트 상품을 샀는데 왜 아직 예약이 아닌가”

환자 A에게는 세 가지 상품 구매가 차례로 발생할 수 있습니다.

시점환자 A의 행위 또는 이벤트상품·구매의 의미예약 서비스가 먼저 보존하는 것
T1이벤트 상품을 구매한다한 번 사용할 수 있는 상품 계약구매 ID와 구매 당시 상품 버전(version)
T2N회 방문 상품을 추가 구매한다여러 회차로 이행할 예약 의무회차별 PlannedTreatment와 반복 간격
T3여러 치료 항목의 패키지를 구매한다항목·선후 조건·자원 요구가 있는 실행 BOM항목별 버전(version) 출처와 의존성(dependency)
T4원하는 날짜를 요청하거나 요청하지 않는다고객의 예약 선호 입력불변 BookingPreferenceSnapshot
T5후보 시간에 동의한다특정 시간·항목·자원에 대한 예약CONFIRMED 상태와 정책 기준 정보
T6내원하고 처치받는다예약 사실과 임상 사실이 이어짐내원·완료 이벤트(event)와 미이행 항목의 상태

이 표에서 핵심은 세 구매를 하나의 Appointment 행으로 합치지 않는다는 점입니다. 이벤트 상품의 한 번 사용, N회 상품의 세 번째 회차, 패키지의 특정 항목은 남은 의무와 선후 조건이 다릅니다. 같은 방문에서 여러 상품의 항목을 함께 처리할 수는 있지만, 방문에 합의된 AppointmentItem과 각 구매의 AppointmentPlan은 계속 별도로 추적해야 합니다.

구매는 환자가 무엇을 사용할 계약을 맺었는지에 대한 상업적 사실입니다. AppointmentPlan은 그 계약을 예약 서비스가 어떤 실행 의무로 해석했는지에 대한 계획입니다. 확정 예약은 특정 시간과 항목, 필요한 자원을 이행하기로 합의한 결과입니다. 세 가지를 같은 레코드로 취급하면 상품 변경이나 일정 변경이 과거 예약을 조용히 덮어쓰게 됩니다.

상품 기준 데이터가 예약 서비스에 들어오는 최소 계약

섹션 제목: “상품 기준 데이터가 예약 서비스에 들어오는 최소 계약”

예약 서비스가 상품명을 읽고 “이 정도면 30분 예약”이라고 추측해서는 안 됩니다. 상품 관리 서비스는 예약에 필요한 기준 데이터를 버전으로 발행하고, 예약 서비스는 그 정의를 구매 시점의 불변 입력으로 보존합니다.

현재 ProductCatalogDefinition에는 다음과 같은 예약 해석 정보가 포함됩니다.

기준 데이터예약 서비스가 해석하는 의미
catalogVersionschemaVersion어떤 상품 계약과 decoder(해석기)로 해석했는가
items의 repeatCount몇 개의 PlannedTreatment를 만들 수 있는가
durationMinutes회차마다 예상되는 자원 점유 시간
minimumIntervalDays, preferredIntervalDays, maximumIntervalDays반복 회차 사이의 필수 제약(hard)·선호 제약(soft) 간격
담당자·장비·진료실(room) 유형후보 시간에 필요한 역량과 자원
dependencies선행 회차가 끝나야 가능한 후행 회차
initialBookingRule고객 희망 일정이 없을 때 최초 제안을 계산하는 제한된 대체 규칙(fallback)

상품 이름이나 가격은 이 계약을 대신할 수 없습니다. sourceAuthority는 상품 기준 데이터를 발행한 기준 데이터 원본을 가리키는 식별자이고, catalogVersion은 그 원본이 발행한 특정 불변 revision입니다. 이 필드를 접근 제어 정보로 읽지 않는 이유도 여기에 있습니다. 이 문맥은 인증·인가가 아니라 “어느 서비스의 기준 데이터를 믿고 해석하는가”를 말합니다.

구매 이벤트에는 구매 기준 데이터 원본과 구매 ID가 함께 들어와야 합니다. 소스의 PurchaseCompletedEvent가 전달되면 예약 서비스는 테넌트·병원·구매 기준 데이터 원본·구매 ID 범위에서 이미 처리한 구매인지 확인하고, 아직 계획이 없을 때만 상품 기준 정보를 사용해 계획을 만듭니다. 같은 구매 이벤트를 다시 받았다고 새 구매로 추측하지 않습니다.

현재 구현에서 구매 한 건은 하나의 AppointmentPlan으로 확장됩니다. 계획은 다음 출처 이력을 남깁니다.

  • sourcePurchaseAuthoritysourcePurchaseId: 구매 사실을 발행한 기준 데이터 원본과 원본 구매 식별자
  • catalogSourceAuthority, productId, catalogVersion: 어떤 상품 기준 데이터를 사용했는가
  • catalogPayloadHash: 재생 시 같은 상품 기준 정보인지 확인할 수 있는 해시(hash)
  • bookingPreference: 구매 시점에 제출된 고객 희망 일정의 불변 기준 정보
  • PlannedTreatment: BOM 항목의 반복 회차와 소요 시간·자원·간격
  • TreatmentDependency: 선행·후행 회차 사이의 방향성 제약

상품 BOM은 예약 서비스가 임의로 다시 정의하는 목록이 아닙니다. 예약 서비스는 검증된 기준 정보를 읽어 실행 계획으로 확장하고, 그 결과를 다시 재현할 수 있도록 보존합니다. 그래서 상품 기준 데이터가 나중에 바뀌어도 이미 생성된 계획의 과거 항목을 최신 카탈로그로 다시 전개하지 않습니다.

PurchaseCompleted
└─> AppointmentPlan
└─> PlannedTreatment 1..N ── dependency/DAG
│ fulfills / attempts
Appointment ──> AppointmentItem 1..N ──> ResourceAllocation 1..N

이 그림에서 아래쪽 Appointment는 실제 방문 단위입니다. 한 방문에 여러 계획에서 온 AppointmentItem을 묶을 수 있지만, 그 항목이 어느 구매의 어떤 PlannedTreatment를 이행하는지는 계속 남아 있어야 합니다. 자원 배정은 고객이 예약에 동의한 뒤 기록되는 예약 사실이고, 구매 이벤트를 받은 순간 자동으로 자원을 점유했다는 뜻이 아닙니다.

희망 일정과 최초 제안 대체 규칙(fallback)을 분리하기

섹션 제목: “희망 일정과 최초 제안 대체 규칙(fallback)을 분리하기”

고객이 “다음 주 화요일 오전”을 요청했다고 해서 그 요청이 확정 시간은 아닙니다. 현재 BookingPreferenceSnapshot은 다음 네 가지 입력을 불변 값으로 보존합니다.

입력의미
ExactDateTime명시한 현지 날짜·시각을 병원 시간대와 UTC 기준 시각으로 정규화한 선호
DateRange허용 가능한 병원 현지 날짜 범위
PreferredWeekdaysAndWindows허용 요일과 현지 시간대 범위
NotProvided고객이 희망 일정을 제공하지 않았다는 명시적인 표시

NotProvided일 때만 상품의 initialBookingRule을 대체 규칙(fallback)으로 검토합니다. 예를 들어 WithinDaysAfterPurchase(maximumDays)는 원본 구매일 이후 제한된 기간 안에 최초 가예약 제안을 만들 수 있다는 규칙입니다. 이 규칙은 자동 확정을 허용하지 않고, 고객이 직접 제출한 희망 일정을 덮어쓰지도 않습니다.

여기서 구매 후 최초 제안 기한상품 이용 만료일을 혼동하면 안 됩니다. 전자는 예약 서비스가 처음 후보를 제안할 수 있는 계산 규칙이고, 후자는 상품 관리부가 정하는 이용 계약입니다. 현재 ProductCatalogDefinition에는 전자를 표현하는 initialBookingRule이 있지만, 상품 이용 만료일을 자동으로 의미하는 필드는 없습니다.

후보 계산은 상품 기준 데이터와 병원 운영 기준 데이터를 함께 읽는 단계입니다. 예상 소요 시간, 필요한 담당자· 장비·진료실(room), 반복 간격, 선행 조건을 만족하더라도 해당 병원의 업무시간과 수용량이 맞지 않으면 후보가 되지 않습니다.

현재 원본에는 계획·희망 입력·예약 정책을 표현하는 모델이 있고, 예약 설계는 고객 요청을 잠정 상태(provisional)로 시작하는 흐름을 정의합니다. 따라서 아래 표에서 “현재 구현”과 “승인된 설계”를 나누어 읽어야 합니다.

단계상태환자 A에게 생기는 업무 의미상태 표지
후보가 계산됨candidate상품을 사용할 수 있는 조건과 특정 시간 후보가 모두 계산됨승인된 설계
제안이 생성됨PROPOSED고객이 검토할 수 있는 시간·항목·자원 조합승인된 설계
자원을 잠시 보류함HELD정책에 따라 짧은 보류(hold)를 둔 후보. 아직 고객 동의 전승인된 설계
고객이 제시된 조건에 동의함CONFIRMED병원과 환자가 특정 예약을 확정함승인된 설계
계획 항목이 실제 이행으로 이어짐SCHEDULED·IN_PROGRESS·COMPLETED예약과 임상 완료가 별도 상태로 진행됨현재 계획 모델

PROPOSEDHELD는 고객에게 보여 줄 후보 또는 잠정 수용량을 표현합니다. 고객이 다른 시간을 원하면 새 제안을 계산해야 하고, 이미 CONFIRMED인 예약을 조용히 옮길 수 없습니다. 확정 예약을 변경하려면 기존 예약을 유지한 채 새 제안을 만들고 고객의 새 동의를 받는 별도 흐름이 필요합니다.

환자 A의 이벤트 상품 구매가 상품 기준 데이터, AppointmentPlan, 후보 시간, PROPOSED 또는 HELD, 고객 동의와 CONFIRMED를 거쳐 내원·완료 이벤트로 이어지는 시간축과 네 가지 예외 분기
구매 기준 데이터와 상품 기준 데이터를 확인한 뒤 후보를 계산하고, 고객 동의가 있을 때만 확정 예약으로 전환합니다. 후보 없음·만료·취소·병원 사정 변경은 각각 다른 업무 예외입니다.

예외는 같은 예약의 실패가 아니다

섹션 제목: “예외는 같은 예약의 실패가 아니다”

예약 서비스가 예외를 하나의 FAILED 값으로만 남기면 상담 서비스와 운영자가 다음 작업을 판단할 수 없습니다. 환자 A의 같은 이벤트 상품이라도 아래 상황은 서로 다른 사실입니다.

상황예약 서비스가 보존하는 사실다음 업무
후보 시간이 없음계산 조건, 계산 시점, 실패 사유, 재검토 가능 여부조건을 바꾼 후보·대체 시간 제안 또는 상담 handoff
PROPOSED·HELD 만료만료된 제안과 보류(hold)를 확정 예약으로 승격하지 않음새 후보를 계산해 새 제안을 만들거나 운영 검토
환자 취소·거부고객의 의사와 기존 상태 이력상품·환불·상담 판단을 해당 기준 데이터 원본으로 전달
병원 사정 변경영향을 받은 자원·시간·계획 항목과 운영 변경새 제안과 고객 동의, 운영·상담 handoff

병원 사정 변경으로 확정 예약을 바꿔야 할 때도 기존 CONFIRMED를 먼저 삭제하지 않습니다. 예약 서비스는 무엇이 언제 영향을 받았는지와 새 제안이 필요하다는 사실을 남기고, 환자에게 설명하고 동의를 받는 일은 상담·운영 흐름과 함께 수행합니다.

노쇼 페널티나 VIP 우선 예약을 이 글의 구현 기능으로 보장하지 않는 이유도 같습니다. 병원은 다음 예약 요청에 추가 확인을 요구하거나, 설명 가능한 우선순위 정책을 둘 수 있습니다. 그러나 그 정책의 기준 데이터와 판단 책임은 예약 서비스의 시간·자원 상태와 분리해야 합니다. 특히 기존 확정 예약을 자동 취소하거나 환자를 영구 블랙리스트로 만드는 정책은 현재 글의 범위가 아닙니다.

서비스별 기준 데이터와 책임 경계

섹션 제목: “서비스별 기준 데이터와 책임 경계”

예약 서비스가 환자 A와 관련된 모든 사실을 소유하는 것은 아닙니다. 각 서비스가 기준 데이터 원본과 책임을 가지고, 예약 서비스는 필요한 객관적 예약 사실을 전달합니다.

업무 영역기준 데이터 원본예약 서비스에 넘기는 사실예약 서비스의 책임
상품 관리·상품 개발상품 버전(version), BOM, 소요 시간, 자원 요구, 최초 예약 규칙카탈로그(catalog) 프로젝션 또는 동기화 이벤트(event)구매 당시 상품 기준 데이터를 검증하고 보존
구매·커머스구매 계약과 원본 구매 IDPurchaseCompleted구매 하나당 계획을 만들고 구매 출처 이력을 보존
예약 서비스AppointmentPlan, 후보·제안·보류·확정 상태, 정책 기준 정보, 이력객관적 예약 이벤트(event)와 지속 보존 아웃박스(outbox)예약 가능 조건·예약·상태 이력을 보존
임상·시술실제 시작·완료·부분 완료완료·이행 사실(completion/fulfillment fact)계획 항목 상태와 후속 예약 영향 반영
고객 상담·CRM고객 프로필(profile), 상담, 민원, 보상 판단예약 지연·취소·재예약 제안 같은 객관적 사실상담이 판단할 수 있는 예약 사실과 인계(handoff) 제공
알림연락처, 언어, 동의, 발송 이력예약 이벤트(event)와 아웃박스(outbox) 처리 결과예약 트랜잭션과 채널 발송을 직접 결합하지 않음
통계·외부 소비자프로젝션과 지표예약 이벤트(event)와 스키마 계약외부 프로젝션에 원본 예약 상태를 양도하지 않음

이 표에서 “기준 데이터”는 단순히 데이터를 보관하는 장소가 아닙니다. 상품 관리부는 상품이 무엇인지, 커머스는 무엇을 구매했는지, 임상 서비스는 무엇을 실제로 수행했는지, CRM은 어떤 상담과 보상을 판단했는지를 각각 설명할 수 있어야 합니다. 예약 서비스는 그 사실들을 임의로 합치지 않고, 일정과 예약에 필요한 부분을 연결합니다.

현재 구현·승인 설계·운영 대기·로드맵

섹션 제목: “현재 구현·승인 설계·운영 대기·로드맵”
사실성 표지이번 글에서 말하는 범위독자가 확인할 질문
현재 구현버전형 상품 기준 데이터 프로젝션, 구매별 AppointmentPlan, PlannedTreatment, 희망 일정 기준 정보와 계획 상태실제 원본과 테스트에서 이 계약을 확인할 수 있는가
승인된 설계후보 계산 뒤 PROPOSED·HELD·CONFIRMED, 동의 기반 변경, 네 가지 예외 분기(branch)설계 문서를 현재 API나 운영 기능으로 과장하고 있지 않은가
운영 대기브로커 전달, 알림 아웃박스(outbox) 카나리, 통계 백필과 운영 준비 상태코드가 있어도 전달·복구를 실제로 검증했는가
로드맵환자 포털에서 제안을 확인하고 동의하는 공개 채널, 노쇼·VIP 정책의 구체화아직 정해지지 않은 정책을 현재 기능으로 약속하고 있지 않은가

이 상태 표지는 상품 변경 글에서 사용한 구분과도 이어집니다. 현재 AppointmentPlan 모델이 존재한다고 해서 모든 병원이 구매 직후 자동으로 특정 시간을 확정하는 것은 아닙니다. 반대로 승인된 예약 설계가 있다고 해서 현재 운영 환경의 후보 계산·알림·상담 채널이 모두 배포됐다는 뜻도 아닙니다.

이번 글은 이벤트 상품 하나가 만드는 첫 번째 예약을 따라가며, 상품 기준 데이터·구매 기준 데이터· 예약 계획·고객 동의의 경계를 고정했습니다. 다음 글인 N회 상품은 왜 예약 한 건이 아닌가에서는 여러 PlannedTreatment가 잔여 권리를 보존하면서 예약을 한 번씩 만드는 과정을 살펴보겠습니다.

아래 보조 자료는 원본 설계 문서를 대신하지 않고, 상품 기준 데이터가 상품 BOM과 예약 계획으로 전개되는 구조를 보조합니다.

댓글

GitHub 계정으로 의견을 남기거나 reaction을 남길 수 있습니다.