[설계 4] 패키지 상품은 왜 실행 그래프가 되는가

패키지 상품을 “상담과 검사, 시술, 사후관리를 한 번에 할인해서 판매하는 상품”이라고만 모델링하면 첫 예약에서 곧바로 문제가 드러납니다. 어떤 항목은 먼저 끝나야 하고, 어떤 항목은 같은 방문에 묶을 수 있으며, 어떤 항목은 같은 상품에 들어 있어도 다른 날 진행해야 합니다. 항목마다 필요한 의료진·장비·공간과 준비·진료·회복 시간도 다릅니다.
앞 글에서 환자 A는 N회 상품을 구매하고, 한 번의 방문을 확정한 뒤 남은 이행 의무를 계속 추적했습니다. 이번에는 같은 환자 A가 상담 → 검사 → 시술 → 사후관리로 이어지는 패키지를 구매했다고 해보겠습니다. 실제 상품명과 병원 정책은 공개하지 않고, 패키지의 예약 운영 특성만 남깁니다.
상품 목록 ≠ 상품 BOM ≠ 예약

상품 개발부가 정의한 패키지 구성은 예약 서비스가 바로 달력에 쓰는 데이터가 아닙니다. 구매 시점의 선택과 상품 버전을 고정한 뒤, 실행 가능한 항목과 관계로 전개해야 합니다. 그 결과가 AppointmentPlan과 PlannedTreatment이고, 고객과 병원이 합의한 한 번의 방문은 그 계획에서 선택된 AppointmentItem의 묶음입니다.
패키지의 상품 목록만 저장하면 첫 예약에서 멈춘다
섹션 제목: “패키지의 상품 목록만 저장하면 첫 예약에서 멈춘다”환자 A의 패키지가 다음 순서로 흘러간다고 하겠습니다. 아래 이름과 관계는 공개된 패키지 보조 자료의 익명 예시를 업무 흐름에 맞게 풀어 쓴 것입니다. 특정 병원의 실제 진료표나 운영 임계값을 뜻하지 않습니다.
| 시점 | 환자 A의 행위 또는 이벤트 | 업무 의미 | 예약 서비스가 보존하는 것 |
|---|---|---|---|
| T1 | 패키지를 구매한다 | 여러 구성 상품을 이용할 계약이 생김 | 구매 ID와 구매 당시 패키지·구성 상품 버전 |
| T2 | 선택 결과와 반복 횟수가 확정된다 | “최신 상품을 나중에 다시 읽기”가 아니라 실행 계약이 고정됨 | 선택된 구성 버전과 상품 BOM 기준 정보 |
| T3 | 구매 완료 이벤트가 전달된다 | 상품 그래프를 예약 계획으로 전개할 입력이 도착함 | 이벤트 출처, 스키마 버전, 기준 정보 해시 |
| T4 | 계획을 전개한다 | 항목별 진료 의무와 선후행 관계가 생김 | AppointmentPlan, PlannedTreatment, 의존성 |
| T5 | 가능한 방문을 제안한다 | 같은 방문으로 묶을 항목과 나눌 항목을 자원·간격으로 판단함 | AppointmentProposal과 항목별 자원 후보 |
| T6 | 고객과 병원이 일정에 동의한다 | 특정 시간·항목·자원을 이행하기로 합의함 | CONFIRMED 제안 리비전과 AppointmentItem |
| T7 | 일부 항목이 완료되거나 일정이 깨진다 | 완료 사실과 미래 작업을 분리해 후속 계획을 계산함 | 완료 근거 이력, 미완료 항목, 새 제안 이력 |
T1의 구매를 Appointment 하나로 저장하면 T2의 선택, T4의 의존성, T5의 자원 충돌을 표현할 자리가 없습니다. 반대로 패키지 전체를 하나의 소요 시간으로 저장하면 상담실, 시술실, 회복 공간을 서로 다른 시간 구간에 배치할 수 없습니다. 패키지는 판매 단위이지만, 예약에서는 실행 단위의 그래프로 다시 읽혀야 합니다.
환자 A의 패키지는 네 가지 핵심 단계와 선택 항목으로 시작한다
섹션 제목: “환자 A의 패키지는 네 가지 핵심 단계와 선택 항목으로 시작한다”환자 A가 선택한 패키지는 설명을 위해 다음 네 가지 핵심 단계와 선택 항목으로 구성합니다.
| 실행 항목 | 구성 방식 | 방문 관계 | 실행 조건과 자원 |
|---|---|---|---|
| 사전 상담 | REQUIRED | 첫 방문에서 진행 | 상담 담당자, 상담실, 상담 시간 |
| 사전 검사 | REQUIRED | 상담과 같은 방문에 묶거나 별도 방문 | 검사 담당자, 검사 공간, 검사 시간, 상담 완료 사실 |
| 본 시술 | REQUIRED | 검사 완료 후 별도 방문 | 시술 담당자, 전용 장비, 시술실, 회복 공간 |
| 진정 관리 | OPTIONAL | 본 시술과 같은 방문에 묶을 수 있음 | 관리 담당자, 관리 장비, 관리 공간 |
| 사후 점검 | REQUIRED | 본 시술 뒤 별도 방문 | 담당 의료진, 진료 공간, 선행 완료 사실 |
이 표의 REQUIRED와 OPTIONAL은 상품 구성 방식입니다. 첫 방문, 별도 방문, 같은 방문 가능은 방문 묶음 제약이고, “상담 완료 후 검사”, “검사 완료 후 본 시술”은 실행 의존성입니다. 세 축을 하나의 isPackage 플래그로 합치면 어떤 규칙이 상품에서 왔고 어떤 규칙이 예약 계산에서 생겼는지 설명할 수 없게 됩니다.
반복·복합·M-of-N은 서로 다른 그래프다
섹션 제목: “반복·복합·M-of-N은 서로 다른 그래프다”공개 보조 자료는 패키지 구성을 세 가지 유형으로 비교합니다. 공통점은 모두 구매 시점의 버전을 고정한다는 것이고, 차이점은 실행 항목과 선택 규칙의 모양입니다.
| 유형 | 예시 | 실행 그래프의 모습 | 예약에서 놓치면 안 되는 사실 |
|---|---|---|---|
| 동일 상품 반복형 | 같은 관리 상품 5회 | 하나의 구성 상품 버전이 quantity=5로 다섯 노드가 됨 | 각 회차의 간격과 완료 여부가 따로 남음 |
| 복합 구성형 | 상담 + 검사 + 시술 + 진정 관리 + 사후 점검 | 서로 다른 버전을 필수·선택·선후행 간선으로 연결함 | 같은 방문 가능 여부와 자원 요구가 항목마다 다름 |
| M-of-N 선택형 | 후보 3개 중 2개 선택 | 고객의 선택 결과가 확정된 뒤 선택된 노드만 상품 BOM에 들어감 | 선택 수가 맞지 않으면 실행 계약을 만들지 않음 |
반복형은 N회 글에서 본 잔여 이행 의무를 패키지 그래프의 여러 노드로 확장한 형태입니다. 복합형은 “모두 하면 좋은 목록”이 아니라 선행 완료와 방문 분리 규칙을 가진 DAG입니다. M-of-N은 고객이 고른 후보가 구매 시점에 확정되어야 하며, 예약 서비스가 나중에 최신 카탈로그를 조회해 임의로 다른 항목을 넣어서는 안 됩니다.
패키지 구성 편집 화면과 상품 BOM 요약은 패키지 상품 구성 보조 자료에서 세 유형을 직접 비교할 수 있습니다. 보조 자료는 승인된 설계 Markdown을 대신하지 않는 설명 보조 자료입니다.
노드와 엣지에는 업무 의미가 있다
섹션 제목: “노드와 엣지에는 업무 의미가 있다”현재 카탈로그 프로젝션의 CatalogBomItem은 단순한 상품명 목록이 아닙니다. 반복 횟수, 회차별 예상 점유 시간, 회차 간 최소·선호·최대 간격, 필요한 담당자 역량·장비·공간을 함께 가집니다. CatalogBomDependency는 항목 사이의 방향성과 간격을 보존합니다.
패키지 설계에서는 이 정보를 다음 세 축으로 분리합니다.
| 축 | 대표 값 | 답하는 질문 |
|---|---|---|
| 실행 의존성 | BLOCKING, NON_BLOCKING | 선행 항목이 끝나지 않으면 후행 항목을 멈춰야 하는가? |
| 방문 묶음 | MUST_SAME_VISIT, MAY_SAME_VISIT, MUST_SEPARATE_VISIT | 두 항목을 한 번의 방문에 함께 배치할 수 있는가? |
| 자원·시간 | 담당자, 장비, 공간, 준비·진료·회복 시간 | 후보 시간에 실제 수용량이 있는가? |
예를 들어 진정 관리는 본 시술과 같은 방문에 묶을 수 있지만, 본 시술이 끝나기 전에 진정 관리만 먼저 확정할 수는 없습니다. 사후 점검은 선행 시술 완료와 일정 간격이 필요하므로 같은 날 한 항목으로 합치지 않습니다. 이 관계를 하나의 durationMinutes와 dependsOn만으로 표현하면 “같은 방문 가능”과 “선행 완료 필요”라는 서로 다른 업무 판단이 충돌합니다.
패키지 전체의 총시간을 저장하는 것은 화면 표시에는 쓸 수 있어도 예약 계산의 원본이 될 수 없습니다. 같은 방문에 묶인 항목도 각자의 준비·진료·회복 구간과 자원 점유를 유지해야 하며, 다른 날의 항목 시간을 단순히 더해 하나의 슬롯으로 만들면 안 됩니다.
환자 A의 핵심 단계는 두 번 또는 세 번의 방문이 된다
섹션 제목: “환자 A의 핵심 단계는 두 번 또는 세 번의 방문이 된다”환자 A가 원하는 날짜를 입력했다고 해서 다섯 실행 항목이 한 번의 예약으로 확정되는 것은 아닙니다. 예약 서비스는 병원 정책, 고객 희망, 실제 자원과 의존성을 합성해 방문 후보를 만듭니다.
| 방문 후보 | 포함할 수 있는 항목 | 왜 나누는가 |
|---|---|---|
| 방문 1 | 사전 상담 + 사전 검사 | 상담 결과와 검사 공간·담당자를 함께 확보할 수 있을 때 묶음 |
| 방문 2 | 본 시술 + 선택한 진정 관리 | 두 항목의 시간·자원이 양립할 때 같은 방문으로 묶을 수 있음 |
| 방문 3 | 사후 점검 | 본 시술 완료 뒤의 간격과 완료 사실이 필요함 |
반대로 상담·검사와 본 시술을 병원의 자원과 안전 규칙이 허용한다면 하나의 방문 후보로 묶을 수 있습니다. 그래도 방문 안의 각 항목은 각각 PlannedTreatment를 참조하는 AppointmentItem으로 남고, 담당자·장비·공간 점유는 항목별로 계산합니다. Appointment는 한 번의 방문을 표현하고, AppointmentPlan은 구매에서 파생된 전체 실행 의무를 표현한다는 경계를 유지하는 이유입니다.
고객이 후보를 거부하거나 새 자원 점유에 실패했을 때도 기존 확정 예약을 먼저 지우지 않습니다. 새 제안 리비전과 자원 점유를 검증한 뒤 고객 동의가 완료될 때만 확정 제안을 교체합니다. 실패하면 기존 confirmedProposalId와 자원 점유를 그대로 유지합니다.
실패 상황은 그래프를 다시 쓰지 않고 영향 범위를 좁힌다
섹션 제목: “실패 상황은 그래프를 다시 쓰지 않고 영향 범위를 좁힌다”패키지가 실행 그래프라는 사실은 정상 경로보다 예외에서 더 분명해집니다. 실패했다고 구매 기준 정보나 완료 사실을 다시 쓰면 환자 A에게 어떤 예약이 있었고 어떤 항목이 끝났는지 설명할 수 없습니다.
| 상황 | 보존해야 하는 사실 | 다음 처리 |
|---|---|---|
| M-of-N 선택 수가 맞지 않음 | 고객이 선택한 후보와 상품 버전 | 구매·상품 단계에서 상품 BOM 발행을 거부하고 예약 계획을 만들지 않음 |
BLOCKING 선행 항목이 미완료 | 선행 항목의 상태와 후행 간선 | 해당 경로만 BLOCKED_REVIEW 또는 대기 대상으로 두고 독립 항목은 계속 계산 |
| 자원 충돌 또는 병원 사정 | 기존 확정 제안과 자원 점유 | 새 후보를 만들되 고객 동의 전까지 기존 예약을 보호 |
| 일부 항목만 완료 | 완료된 PlannedTreatment의 임상 근거 이력 | 완료 항목은 유지하고 미완료 항목만 후속 AppointmentItem 시도로 전개 |
| 패키지 버전이 변경됨 | 구매 당시 패키지·구성 상품 버전과 상품 BOM | 상품팀의 전환표·승인·동의가 있을 때만 같은 Plan에 새 리비전을 추가 |
특히 패키지 버전이 바뀌었다고 기존 구매가 최신 카탈로그를 자동으로 따라가면 안 됩니다. 새 버전은 이후 구매의 기준이고, 기존 구매는 구매 당시 패키지 버전·구성 상품 버전·선택 결과·상품 BOM을 참조합니다. 예외적인 전환이 필요하면 상품 관리 서비스가 의미를 알고 있는 전환표와 동의 증빙을 발행하고, 예약 서비스는 그 사실을 검증한 뒤 미진행 항목만 새 리비전으로 승계합니다. 이미 완료된 항목과 고객이 동의한 확정 예약은 보호합니다.
서비스별 책임을 그래프의 경계에 함께 기록한다
섹션 제목: “서비스별 책임을 그래프의 경계에 함께 기록한다”패키지 실행 그래프를 예약 서비스가 전부 소유한다는 뜻은 아닙니다. 각 서비스가 기준 데이터 원본을 소유하고, 예약 서비스는 예약 판단에 필요한 불변 기준 데이터와 객관적 이벤트를 보존합니다.
| 업무 영역 | 기준 데이터 원본 | 예약 서비스가 맡는 책임 |
|---|---|---|
| 상품 관리·상품 개발 | 상품 버전, 구성 그래프, BOM, 선택·반복 규칙 | 검증된 상품 프로젝션과 구매 시 상품 BOM 근거 이력을 예약 판단에 사용 |
| 구매·커머스 | 구매 계약, 선택 결과, 환불, 원본 구매 ID | 구매 완료 사실마다 계획 식별자를 만들고 취소 범위를 반영 |
| 예약 서비스 | AppointmentPlan, PlannedTreatment, 제안, 보류(hold), 확정 예약, 자원 점유 | 시간·수용량·동의·상태·이력과 객관적 예약 이벤트 소유 |
| 임상·시술 | 실제 시작·완료·부분 완료 | 완료 근거를 발행하고 계획의 후속 가능 범위를 결정 |
| 고객 상담·CRM | 고객 프로필 정보, 상담, 민원, 보상, 서비스 등급 판단 | 노쇼·지연·재예약 같은 객관적 사실을 받아 상담 판단으로 연결 |
| 알림·통계 소비자 | 연락 동의, 발송 이력, 프로젝션, 지표 | 예약 트랜잭션과 분리해 아웃박스(outbox)와 조회 모델을 처리 |
따라서 예약 서비스가 고객의 보상이나 VIP 등급을 직접 결정하지 않습니다. 그런 정책이 필요하더라도 CRM·상품·병원 운영 정책이 책임과 근거를 정의하고, 예약 서비스는 기존 예약과 의료 자원을 보호하면서 공정한 순서로 제안을 만드는 데 필요한 입력과 결과만 기록해야 합니다. 구체적인 노쇼 다음 예약과 우선순위 정책은 이 시리즈의 후속 운영 글에서 별도로 다룹니다.
현재 구현과 승인된 설계를 구분해 읽기
섹션 제목: “현재 구현과 승인된 설계를 구분해 읽기”패키지 업무를 설명할 때 모델 이름만 보고 모든 경로가 운영 중이라고 단정하지 않도록 사실성 표지를 붙입니다.
| 사실성 표지 | 이번 글에서 확인한 범위 | 독자가 다시 확인할 질문 |
|---|---|---|
| 현재 구현 | ProductCatalogDefinition의 버전·BOM 항목·의존성 프로젝션, 반복·시간·자원·간격 필드, PurchaseCompletedHandler의 구매 이벤트 검증과 계획 생성·중복·오래된·격리 결과 | develop 원본과 테스트에서 동일한 계약을 확인할 수 있는가? |
| 승인된 설계 | 패키지 구성 그래프, 선택 결과가 고정된 PackageExecutionSnapshot, 방문 묶음 제약, AppointmentItem·ResourceAllocation, 제안/동의와 Plan 리비전 | 설계 문서를 이미 배포된 API로 오해하고 있지 않은가? |
| 운영 대기 | 브로커·임상·커머스 이벤트 연동, 알림 아웃박스(outbox) 카나리, 운영 백필과 재생·복구 검증 | 실제 환경에서 전달과 복구를 확인했는가? |
| 로드맵 | 환자 채널에서 후속 제안을 고르는 화면, 구체적인 노쇼 페널티와 VIP 우선순위 정책 | 아직 정하지 않은 정책을 현재 상품 계약으로 약속하고 있지 않은가? |
현재 구현은 구매와 카탈로그를 계획으로 연결하는 기반을 제공합니다. 승인된 패키지 설계는 그 기반 위에 상품 BOM, 방문 후보, 항목별 자원, 동의와 리비전을 추가할 경계를 정의합니다. 두 범위를 섞지 않아야 구현된 사실과 앞으로 검증할 업무 계약을 독자에게 정확히 설명할 수 있습니다.
다음 글에서 다룰 것
섹션 제목: “다음 글에서 다룰 것”패키지 그래프가 만들어졌다고 환자 A의 달력에 방문이 자동으로 생기지는 않습니다. 다음 글 상품 BOM은 어떻게 AppointmentPlan과 방문 계획으로 이어지는가에서는 구매 이벤트에 담긴 상품 BOM이 AppointmentPlan 리비전, PlannedTreatment, 한 번의 Appointment와 여러 AppointmentItem으로 이어지는 경로를 따라가겠습니다. 계획 생성과 방문 확정, 실제 임상 완료를 어디에서 분리하는지가 다음 질문입니다.
시각 자료로 다시 보기
섹션 제목: “시각 자료로 다시 보기”아래 보조 자료는 원본 설계 Markdown과 clinic-appointment 저장소를 대신하지 않고, 패키지 구성을 읽는 순서를 보조합니다.
근거 링크
섹션 제목: “근거 링크”- clinic-appointment 저장소
- 패키지 실행 그래프와 예약 설계
- 상품 카탈로그 정의
- AppointmentPlan 모델
- AppointmentPlan 리비전 모델
- 구매 완료 이벤트 처리
- 상품·구매·예약 데이터 흐름
댓글
GitHub 계정으로 의견을 남기거나 reaction을 남길 수 있습니다.