ARI Package는 여러 요금제(Rate Plan)를 하나의 패키지로 묶어 관리하는 기능을 제공합니다. 패키지를 통해 특정 기간이나 조건에 따라 다른 요금제를 적용할 수 있으며, 고객에게 다양한 예약 옵션을 제공할 수 있습니다.
주요 개념:
- 패키지: 하나 이상의 요금제를 포함하는 컨테이너
- 기간별 요금제: 체크인/체크아웃 날짜에 따라 자동으로 적용되는 요금제
- 예약 타입별 분류: 대실(rent) 또는 숙박(lodge) 패키지
- 활성화 관리: 패키지 노출 여부 제어
Queries
getAriPackageList
특정 숙박 시설의 패키지 목록을 조회합니다.
GraphQL Signature
query GetAriPackageList(
$accommodationId: ID!
$filter: AriPackageFilterInput
) {
getAriPackageList(accommodationId: $accommodationId, filter: $filter) {
id
name
code
reservationType
isActive
sortOrder
description
iconUrl
rateplans {
id
name
code
baseOccupancy
checkInAt
checkOutAt
displayPeriod {
name
startDate
endDate
}
}
}
}
파라미터
필터 조건
isActive: 활성화 상태 필터 (true/false)
type: 예약 타입 필터 (rent/lodge)
활성화 여부 (비활성화 시 고객에게 노출되지 않음)
query {
getAriPackageList(
accommodationId: "01H8X9Y2Z3A4B5C6D7E8F9G0H1"
filter: { isActive: true, type: lodge }
) {
id
name
code
reservationType
isActive
sortOrder
description
rateplans {
name
baseOccupancy
displayPeriod {
name
startDate
endDate
}
}
}
}
Mutations
createAriPackage
새로운 패키지를 생성합니다.
GraphQL Signature
mutation CreateAriPackage($accommodationId: ID!, $input: CreateAriPackageInput!) {
createAriPackage(accommodationId: $accommodationId, input: $input) {
id
name
code
reservationType
isActive
sortOrder
description
iconUrl
rateplans {
id
name
}
}
}
파라미터
input
CreateAriPackageInput!
required
패키지 생성 정보
패키지 코드 (숙박 시설 내에서 고유해야 함)
input.reservationType
NormalReservationType!
required
예약 타입 (rent/lodge)
생성된 AriPackage 객체를 반환합니다.
mutation {
createAriPackage(
accommodationId: "01H8X9Y2Z3A4B5C6D7E8F9G0H1"
input: {
name: "주말 특가 패키지"
code: "WEEKEND_SPECIAL"
reservationType: lodge
isActive: true
sortOrder: 10
description: "주말 숙박 특별 할인 패키지"
iconUrl: "https://example.com/icons/weekend.png"
ratePlanIds: [1, 2, 3]
}
) {
id
name
code
reservationType
isActive
rateplans {
id
name
}
}
}
검증 규칙
- 동일한
accommodationId와 code 조합이 이미 존재하면 ARI_PACKAGE.CODE_ALREADY_EXISTS 에러 발생
- 이벤트 소싱 패턴을 사용하여 비동기로 생성됨
updateAriPackage
기존 패키지를 수정합니다.
GraphQL Signature
mutation UpdateAriPackage($id: ID!, $input: UpdateAriPackageInput!) {
updateAriPackage(id: $id, input: $input) {
id
name
code
reservationType
isActive
sortOrder
description
iconUrl
rateplans {
id
name
}
}
}
파라미터
input
UpdateAriPackageInput!
required
수정할 필드 (모든 필드 선택적)
패키지에 포함할 요금제 ID 목록 (전체 교체)
수정된 AriPackage 객체를 반환합니다.
mutation {
updateAriPackage(
id: "01H9Z1A2B3C4D5E6F7G8H9I0J1"
input: {
name: "주말 프리미엄 패키지"
isActive: true
sortOrder: 5
ratePlanIds: [1, 2]
}
) {
id
name
sortOrder
isActive
rateplans {
id
name
}
}
}
검증 규칙
- 패키지 코드 변경 시 중복 검증 실행
- 이벤트 소싱 패턴을 사용하여 비동기로 수정됨
- 패키지 히스토리가 자동으로 생성됨
deleteAriPackage
패키지를 삭제합니다.
GraphQL Signature
mutation DeleteAriPackage($id: ID!) {
deleteAriPackage(id: $id)
}
파라미터
mutation {
deleteAriPackage(id: "01H9Z1A2B3C4D5E6F7G8H9I0J1")
}
- 이벤트 소싱 패턴을 사용하여 비동기로 삭제됨
- 삭제된 패키지는 복구할 수 없으며, 히스토리는 유지됨
특수 필드
appliedRatePlans
특정 체크인/체크아웃 기간 동안 날짜별로 적용되는 요금제를 조회합니다.
GraphQL Signature
query GetAppliedRatePlans(
$accommodationId: ID!
$checkInAt: Date!
$checkOutAt: Date!
) {
getAriPackageList(accommodationId: $accommodationId) {
id
name
appliedRatePlans(checkInAt: $checkInAt, checkOutAt: $checkOutAt) {
date
ratePlan {
id
name
checkInAt
checkOutAt
baseRate {
amount
currency
}
}
}
}
}
파라미터
해당 날짜에 적용되는 요금제 (없으면 null)
동작 방식
- 패키지에 포함된 각 요금제의
displayPeriod를 확인
- 요청한 날짜 범위 내에서 각 날짜별로 적용 가능한 요금제를 찾음
- 날짜별로 하나의 요금제만 적용됨 (첫 번째로 매칭되는 요금제)
query {
getAriPackageList(accommodationId: "01H8X9Y2Z3A4B5C6D7E8F9G0H1") {
id
name
appliedRatePlans(
checkInAt: "2024-07-15"
checkOutAt: "2024-07-17"
) {
date
ratePlan {
name
baseRate {
amount
currency
}
}
}
}
}
패키지 설계 패턴
1. 시즌별 패키지
성수기/비수기별로 다른 요금제를 적용:
{
name: "시즌별 패키지"
reservationType: lodge
ratePlanIds: [
1, # 성수기 요금제 (7-8월)
2 # 비수기 요금제 (12-2월)
]
}
2. 요일별 패키지
주중/주말별로 다른 요금제를 적용:
{
name: "요일별 패키지"
reservationType: lodge
ratePlanIds: [
3, # 평일 요금제 (월-목)
4 # 주말 요금제 (금-일)
]
}
3. 대실/숙박 패키지
대실과 숙박을 별도 패키지로 관리:
# 대실 패키지
{
name: "대실 패키지"
reservationType: rent
ratePlanIds: [5, 6]
}
# 숙박 패키지
{
name: "숙박 패키지"
reservationType: lodge
ratePlanIds: [7, 8]
}
4. 프로모션 패키지
특정 기간에만 활성화되는 프로모션:
{
name: "여름 프로모션"
isActive: true
ratePlanIds: [9, 10]
}
# 프로모션 종료 시 isActive: false로 변경
사용 흐름
- 요금제 생성: 먼저 필요한 요금제들을 생성
- 기간 설정: 각 요금제에
displayPeriod 설정
- 패키지 생성:
createAriPackage로 요금제를 묶어 패키지 생성
- 활성화:
isActive: true로 설정하여 고객에게 노출
- 조회: 고객 예약 시
appliedRatePlans로 적용 가능한 요금제 확인
- 관리: 필요 시 패키지 수정 또는 비활성화
이벤트 소싱
패키지는 이벤트 소싱 패턴을 사용합니다:
- 비동기 처리: 생성/수정/삭제 작업이 비동기로 처리됨
- 이벤트 추적: 모든 변경 사항이 이벤트로 기록됨
- 히스토리 관리: 패키지 변경 이력이 자동으로 저장됨
# Saga 패턴으로 완료 대기
const sagaWaiter = await eventManager.created({
aggregate: "ARI_PACKAGE",
streamId: ulid(),
data: { accommodationId, ...input }
});
const result = await sagaWaiter.waitSaga();
관련 API