Skip to main content

개요

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
      }
    }
  }
}

파라미터

accommodationId
ID!
required
조회할 숙박 시설 ID
filter
AriPackageFilterInput
필터 조건
  • isActive: 활성화 상태 필터 (true/false)
  • type: 예약 타입 필터 (rent/lodge)

응답

id
String!
패키지 ID (ULID 형식)
name
String!
패키지 이름
code
String!
패키지 코드 (고유 식별자)
reservationType
NormalReservationType!
예약 타입:
  • rent: 대실
  • lodge: 숙박
isActive
Boolean!
활성화 여부 (비활성화 시 고객에게 노출되지 않음)
sortOrder
Int!
정렬 순서 (낮은 숫자가 먼저 표시됨)
description
String
패키지 설명
iconUrl
String
패키지 아이콘 이미지 URL
rateplans
[AriRatePlan!]!
패키지에 포함된 요금제 목록

예제

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
    }
  }
}

파라미터

accommodationId
ID!
required
숙박 시설 ID
input
CreateAriPackageInput!
required
패키지 생성 정보
input.name
String!
required
패키지 이름
input.code
String!
required
패키지 코드 (숙박 시설 내에서 고유해야 함)
input.reservationType
NormalReservationType!
required
예약 타입 (rent/lodge)
input.isActive
Boolean
활성화 여부 (기본값: true)
input.sortOrder
Int
정렬 순서 (기본값: 0)
input.description
String
패키지 설명
input.iconUrl
String
패키지 아이콘 이미지 URL
input.ratePlanIds
[Int!]
패키지에 포함할 요금제 ID 목록

응답

생성된 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
    }
  }
}

검증 규칙

  • 동일한 accommodationIdcode 조합이 이미 존재하면 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
    }
  }
}

파라미터

id
ID!
required
수정할 패키지 ID
input
UpdateAriPackageInput!
required
수정할 필드 (모든 필드 선택적)
input.name
String
패키지 이름
input.code
String
패키지 코드
input.reservationType
NormalReservationType
예약 타입 (rent/lodge)
input.isActive
Boolean
활성화 여부
input.sortOrder
Int
정렬 순서
input.description
String
패키지 설명
input.iconUrl
String
패키지 아이콘 이미지 URL
input.ratePlanIds
[Int!]
패키지에 포함할 요금제 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)
}

파라미터

id
ID!
required
삭제할 패키지 ID

응답

success
Boolean!
삭제 성공 여부

예제

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
        }
      }
    }
  }
}

파라미터

checkInAt
Date!
required
체크인 날짜
checkOutAt
Date!
required
체크아웃 날짜

응답

date
String!
날짜 (YYYY-MM-DD 형식)
ratePlan
AriRatePlan
해당 날짜에 적용되는 요금제 (없으면 null)

동작 방식

  1. 패키지에 포함된 각 요금제의 displayPeriod를 확인
  2. 요청한 날짜 범위 내에서 각 날짜별로 적용 가능한 요금제를 찾음
  3. 날짜별로 하나의 요금제만 적용됨 (첫 번째로 매칭되는 요금제)

예제

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로 변경

사용 흐름

  1. 요금제 생성: 먼저 필요한 요금제들을 생성
  2. 기간 설정: 각 요금제에 displayPeriod 설정
  3. 패키지 생성: createAriPackage로 요금제를 묶어 패키지 생성
  4. 활성화: isActive: true로 설정하여 고객에게 노출
  5. 조회: 고객 예약 시 appliedRatePlans로 적용 가능한 요금제 확인
  6. 관리: 필요 시 패키지 수정 또는 비활성화

이벤트 소싱

패키지는 이벤트 소싱 패턴을 사용합니다:
  • 비동기 처리: 생성/수정/삭제 작업이 비동기로 처리됨
  • 이벤트 추적: 모든 변경 사항이 이벤트로 기록됨
  • 히스토리 관리: 패키지 변경 이력이 자동으로 저장됨
# Saga 패턴으로 완료 대기
const sagaWaiter = await eventManager.created({
  aggregate: "ARI_PACKAGE",
  streamId: ulid(),
  data: { accommodationId, ...input }
});
const result = await sagaWaiter.waitSaga();

관련 API