> ## Documentation Index
> Fetch the complete documentation index at: https://api-docs.vpms.io/llms.txt
> Use this file to discover all available pages before exploring further.

# 객실 관리 (Room)

> 객실 및 객실 타입 관리 API

## 개요

Core 서비스의 객실 도메인은 숙박 시설의 객실 및 객실 타입을 관리하는 API를 제공합니다. 객실 타입(RoomType)은 객실의 분류이며, 객실(Room)은 실제 물리적 객실을 나타냅니다. 객실 상태, 청소 상태, 점유 타임라인, 가격 정보 등을 관리할 수 있습니다.

## Queries

### getSingleRoomType

특정 객실 타입의 상세 정보를 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetSingleRoomType($id: ID!) {
  getSingleRoomType(id: $id) {
    id
    name
    description
    accommodationId
    priority
    defaultSleeps
    maxSleeps
    alias
    isDefault
    thumbnail(size: ThumbnailSize)
    totalCount
    saleStateDisableCount
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  조회할 객실 타입 ID
</ParamField>

#### 응답

<ResponseField name="id" type="ID!">
  객실 타입 고유 식별자
</ResponseField>

<ResponseField name="name" type="String!">
  객실 타입 이름 (예: "디럭스", "스위트")
</ResponseField>

<ResponseField name="description" type="String">
  객실 타입 설명
</ResponseField>

<ResponseField name="accommodationId" type="ID!">
  소속 숙박시설 ID
</ResponseField>

<ResponseField name="priority" type="Int">
  우선순위 (높을수록 우선)
</ResponseField>

<ResponseField name="defaultSleeps" type="Int">
  기본 숙박 인원
</ResponseField>

<ResponseField name="maxSleeps" type="Int">
  최대 숙박 인원
</ResponseField>

<ResponseField name="totalCount" type="Int">
  해당 타입의 전체 객실 수
</ResponseField>

<ResponseField name="saleStateDisableCount" type="Int">
  판매 중지된 객실 수
</ResponseField>

#### 권한

* 로그인 필요

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  query {
    getSingleRoomType(id: "01HQKS9V8X2N3P4Q5R6S7T8U9V") {
      id
      name
      description
      defaultSleeps
      maxSleeps
      totalCount
      thumbnail(size: MEDIUM)
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "getSingleRoomType": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9V",
        "name": "디럭스 더블",
        "description": "킹 사이즈 침대가 있는 넓은 객실",
        "defaultSleeps": 2,
        "maxSleeps": 3,
        "totalCount": 10,
        "thumbnail": "https://cdn.example.com/roomtypes/medium/abc123.jpg"
      }
    }
  }
  ```
</CodeGroup>

***

### getSingleRoom

특정 객실의 상세 정보를 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetSingleRoom($id: ID!) {
  getSingleRoom(id: $id) {
    id
    name
    roomTypeId
    accommodationId
    state
    cleanState
    saleState
    calculatedState
    order
    priority
    rcuId
    ccuId
    currentReservation {
      id
      guestName
      useStartAt
      useExpireAt
    }
    upcomingReservation {
      id
      guestName
      useStartAt
      useExpireAt
    }
    amenities {
      name
      icon
    }
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  조회할 객실 ID
</ParamField>

#### 응답

<ResponseField name="id" type="ID!">
  객실 고유 식별자
</ResponseField>

<ResponseField name="name" type="String!">
  객실 번호/이름 (예: "101호", "A동 202호")
</ResponseField>

<ResponseField name="roomTypeId" type="ID!">
  소속 객실 타입 ID
</ResponseField>

<ResponseField name="state" type="RoomState">
  객실 상태: - `NOT_USING`: 미사용 - `USING`: 사용중 - `LEFT`: 퇴실 -
  `SELECTED`: 선택됨 - `POWER_DOWN`: 전원 차단
</ResponseField>

<ResponseField name="cleanState" type="CleanState">
  청소 상태: - `CLEAN`: 청소 완료 - `DIRTY`: 청소 필요 - `CLEANING`: 청소중 -
  `NEED_CLEANING`: 청소 요망 - `URGENT_CLEANING`: 긴급 청소 필요 - `INSPECTION`:
  점검중 - `NEED_INSPECTION`: 점검 필요
</ResponseField>

<ResponseField name="saleState" type="SaleState">
  판매 상태: - `ALL`: 전체 판매 - `OTA`: OTA 전용 - `DISABLED`: 판매 중지
</ResponseField>

<ResponseField name="calculatedState" type="CalculatedState">
  계산된 복합 상태 (state, cleanState, 예약 정보를 종합): - `available`: 판매
  가능 - `availableDirty`: 판매 가능 (청소 필요) - `cleaning`: 청소중 -
  `usingRental`: 대실 사용중 - `usingStay`: 숙박 사용중 - `reservedRental`: 대실
  예약 - `reservedStay`: 숙박 예약 - `expired`: 만료됨 - `disabled`: 판매 중지 -
  기타 다양한 상태 조합
</ResponseField>

<ResponseField name="currentReservation" type="Reservation">
  현재 진행중인 예약 정보
</ResponseField>

<ResponseField name="upcomingReservation" type="Reservation">
  다음 예정된 예약 정보
</ResponseField>

<ResponseField name="amenities" type="[Amenity]">
  객실 편의시설 목록
</ResponseField>

#### 권한

* 로그인 필요

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  query {
    getSingleRoom(id: "01HQKS9V8X2N3P4Q5R6S7T8U9W") {
      id
      name
      state
      cleanState
      calculatedState
      currentReservation {
        id
        guestName
        useStartAt
        useExpireAt
      }
      amenities {
        name
        icon
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "getSingleRoom": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9W",
        "name": "101호",
        "state": "USING",
        "cleanState": "CLEAN",
        "calculatedState": "usingStay",
        "currentReservation": {
          "id": "01HQKS9V8X2N3P4Q5R6S7T8U9X",
          "guestName": "홍길동",
          "useStartAt": "2025-12-23T15:00:00Z",
          "useExpireAt": "2025-12-24T11:00:00Z"
        },
        "amenities": [
          {
            "name": "WiFi",
            "icon": "https://cdn.example.com/icons/wifi.svg"
          },
          {
            "name": "TV",
            "icon": "https://cdn.example.com/icons/tv.svg"
          }
        ]
      }
    }
  }
  ```
</CodeGroup>

***

### getRoomOccupancyTimelines

객실 점유 타임라인을 조회합니다. 특정 기간 동안의 객실 점유 상태를 확인할 수 있습니다.

#### GraphQL Signature

```graphql theme={null}
query GetRoomOccupancyTimelines(
  $accommodationId: ID!
  $filter: RoomOccupancyTimelineFilterInput
  $first: Int
  $after: String
) {
  getRoomOccupancyTimelines(
    accommodationId: $accommodationId
    filter: $filter
    first: $first
    after: $after
  ) {
    edges {
      cursor
      node {
        id
        roomId
        roomTypeId
        reservationId
        occupancyStatus
        startAt
        endAt
        note
        isIncludedToQuantity
      }
    }
    pageInfo {
      hasNextPage
      hasPreviousPage
    }
  }
}
```

#### 파라미터

<ParamField path="accommodationId" type="ID!" required>
  숙박시설 ID
</ParamField>

<ParamField path="filter" type="RoomOccupancyTimelineFilterInput">
  필터 옵션: - `roomTypeId`: 특정 객실 타입으로 필터링 - `roomId`: 특정 객실으로
  필터링 - `sortKey`: 정렬 기준 (기본값: `startAt`) - `sortDirection`: 정렬 방향
  (`asc` 또는 `desc`)
</ParamField>

<ParamField path="first" type="Int">
  조회할 항목 수 (기본값: 20)
</ParamField>

<ParamField path="after" type="String">
  페이지네이션 커서
</ParamField>

#### 응답

<ResponseField name="edges" type="[Edge]">
  타임라인 항목 배열
</ResponseField>

<ResponseField name="pageInfo" type="PageInfo">
  페이지네이션 정보
</ResponseField>

#### 권한

* 숙박시설 관리 권한 필요

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  query {
    getRoomOccupancyTimelines(
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      filter: {
        roomTypeId: "01HQKS9V8X2N3P4Q5R6S7T8U9W"
        sortKey: "startAt"
        sortDirection: "asc"
      }
      first: 20
    ) {
      edges {
        node {
          id
          roomId
          occupancyStatus
          startAt
          endAt
          note
        }
      }
      pageInfo {
        hasNextPage
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "getRoomOccupancyTimelines": {
        "edges": [
          {
            "node": {
              "id": "01HQKS9V8X2N3P4Q5R6S7T8U9X",
              "roomId": "01HQKS9V8X2N3P4Q5R6S7T8U9Y",
              "occupancyStatus": "OCCUPIED",
              "startAt": "2025-12-23T15:00:00Z",
              "endAt": "2025-12-24T11:00:00Z",
              "note": "일반 예약"
            }
          }
        ],
        "pageInfo": {
          "hasNextPage": false
        }
      }
    }
  }
  ```
</CodeGroup>

***

## Mutations

### createRoomType

새로운 객실 타입을 생성합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateRoomType($input: CreateRoomTypeInput!) {
  createRoomType(input: $input) {
    id
    name
    description
    accommodationId
    priority
    defaultSleeps
    maxSleeps
    alias
  }
}
```

#### 파라미터

<ParamField path="input" type="CreateRoomTypeInput!" required>
  객실 타입 생성 정보
</ParamField>

<ParamField path="input.name" type="String!" required>
  객실 타입 이름 (예: "스탠다드", "디럭스", "스위트")
</ParamField>

<ParamField path="input.accommodationId" type="ID!" required>
  소속 숙박시설 ID
</ParamField>

<ParamField path="input.description" type="String">
  객실 타입 설명
</ParamField>

<ParamField path="input.priority" type="Int">
  우선순위 (높을수록 우선)
</ParamField>

<ParamField path="input.defaultSleeps" type="Int">
  기본 숙박 인원
</ParamField>

<ParamField path="input.maxSleeps" type="Int">
  최대 숙박 인원
</ParamField>

<ParamField path="input.alias" type="String">
  객실 타입 별칭
</ParamField>

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요
* 활성화된 숙박시설만 가능

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createRoomType(
      input: {
        name: "디럭스 더블"
        accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
        description: "킹 사이즈 침대가 있는 넓은 객실"
        defaultSleeps: 2
        maxSleeps: 3
        priority: 10
      }
    ) {
      id
      name
      description
      defaultSleeps
      maxSleeps
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createRoomType": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9W",
        "name": "디럭스 더블",
        "description": "킹 사이즈 침대가 있는 넓은 객실",
        "defaultSleeps": 2,
        "maxSleeps": 3
      }
    }
  }
  ```
</CodeGroup>

#### 에러 처리

<ResponseField name="DUPLICATED_DATA_FOUND">
  동일한 이름의 객실 타입이 이미 존재합니다.
</ResponseField>

<ResponseField name="REQUIRED_ACTIVATED_ACCOMMODATION">
  활성화되지 않은 숙박시설에는 객실 타입을 생성할 수 없습니다.
</ResponseField>

***

### updateRoomType

객실 타입 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateRoomType($input: UpdateRoomTypeInput!) {
  updateRoomType(input: $input) {
    id
    name
    description
    priority
    defaultSleeps
    maxSleeps
  }
}
```

#### 파라미터

<ParamField path="input.id" type="ID!" required>
  수정할 객실 타입 ID
</ParamField>

<ParamField path="input.name" type="String">
  객실 타입 이름
</ParamField>

<ParamField path="input.description" type="String">
  객실 타입 설명
</ParamField>

<ParamField path="input.priority" type="Int">
  우선순위
</ParamField>

<ParamField path="input.defaultSleeps" type="Int">
  기본 숙박 인원
</ParamField>

<ParamField path="input.maxSleeps" type="Int">
  최대 숙박 인원
</ParamField>

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요

***

### deleteRoomType

객실 타입을 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteRoomType($id: ID!) {
  deleteRoomType(id: $id) {
    result
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  삭제할 객실 타입 ID
</ParamField>

#### 제약사항

* 해당 타입에 속한 객실이 있으면 삭제 불가
* 기본 객실 타입이면서 유일한 타입인 경우 삭제 불가

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요

#### 에러 처리

<ResponseField name="ROOM_TYPE_HAS_ROOM">
  해당 객실 타입에 속한 객실이 존재하여 삭제할 수 없습니다.
</ResponseField>

***

### createRoom

새로운 객실을 생성합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateRoom($input: CreateRoomInput!) {
  createRoom(input: $input) {
    id
    name
    roomTypeId
    accommodationId
    state
    saleState
    order
    priority
    rcuId
    ccuId
    key
  }
}
```

#### 파라미터

<ParamField path="input" type="CreateRoomInput!" required>
  객실 생성 정보
</ParamField>

<ParamField path="input.name" type="String!" required>
  객실 번호/이름 (예: "101호", "A동 202호")
</ParamField>

<ParamField path="input.accommodationId" type="ID!" required>
  소속 숙박시설 ID
</ParamField>

<ParamField path="input.roomTypeId" type="ID">
  소속 객실 타입 ID (미지정시 기본 객실 타입 사용)
</ParamField>

<ParamField path="input.state" type="RoomState">
  초기 객실 상태 (기본값: `NOT_USING`)
</ParamField>

<ParamField path="input.saleState" type="SaleState">
  판매 상태 (기본값: `ALL`)
</ParamField>

<ParamField path="input.order" type="Int">
  정렬 순서
</ParamField>

<ParamField path="input.priority" type="Int">
  우선순위
</ParamField>

<ParamField path="input.rcuId" type="String">
  RCU(Room Control Unit) ID
</ParamField>

<ParamField path="input.ccuId" type="String">
  CCU(Central Control Unit) ID
</ParamField>

<ParamField path="input.encryptionKey" type="String">
  암호화 키
</ParamField>

<ParamField path="input.amenities" type="[AmenityInput]">
  편의시설 목록
</ParamField>

#### 응답

<ResponseField name="key" type="String">
  자동 생성된 Mifare 카드 키
</ResponseField>

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요
* 활성화된 숙박시설만 가능

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createRoom(
      input: {
        name: "101호"
        accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
        roomTypeId: "01HQKS9V8X2N3P4Q5R6S7T8U9W"
        state: NOT_USING
        saleState: ALL
        priority: 10
        amenities: [{ name: "WiFi", icon: "wifi" }, { name: "TV", icon: "tv" }]
      }
    ) {
      id
      name
      key
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createRoom": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9X",
        "name": "101호",
        "key": "A1B2C3D4E5F6"
      }
    }
  }
  ```
</CodeGroup>

#### 에러 처리

<ResponseField name="DUPLICATED_DATA_FOUND">
  동일한 이름의 객실이 이미 존재합니다.
</ResponseField>

<ResponseField name="INVALID_PARAMETER">
  편의시설 이름 또는 아이콘에 허용되지 않는 문자가 포함되어 있습니다.
</ResponseField>

***

### updateRoom

객실 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateRoom($input: UpdateRoomInput!) {
  updateRoom(input: $input) {
    id
    name
    roomTypeId
    state
    saleState
    cleanState
    order
    priority
    amenities {
      name
      icon
    }
  }
}
```

#### 파라미터

<ParamField path="input.id" type="ID!" required>
  수정할 객실 ID
</ParamField>

<ParamField path="input.name" type="String">
  객실 번호/이름
</ParamField>

<ParamField path="input.roomTypeId" type="ID">
  객실 타입 ID
</ParamField>

<ParamField path="input.state" type="RoomState">
  객실 상태
</ParamField>

<ParamField path="input.saleState" type="SaleState">
  판매 상태
</ParamField>

<ParamField path="input.cleanState" type="CleanState">
  청소 상태
</ParamField>

<ParamField path="input.order" type="Int">
  정렬 순서
</ParamField>

<ParamField path="input.priority" type="Int">
  우선순위
</ParamField>

<ParamField path="input.amenities" type="[AmenityInput]">
  편의시설 목록
</ParamField>

#### 권한

* 숙박시설 스태프(STAFF) 이상 권한 필요

***

### updateRooms

여러 객실을 일괄 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateRooms($input: [UpdateRoomInput!]!) {
  updateRooms(input: $input) {
    id
    name
    state
    saleState
  }
}
```

#### 파라미터

<ParamField path="input" type="[UpdateRoomInput!]!" required>
  수정할 객실 정보 배열
</ParamField>

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요

#### 특징

* 일괄 처리를 위해 트랜잭션 사용
* 각 객실별 감사 로그 자동 기록

***

### deleteRoom

객실을 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteRoom($id: ID!) {
  deleteRoom(id: $id) {
    result
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  삭제할 객실 ID
</ParamField>

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요

***

### setRoomState

객실 상태를 변경합니다.

#### GraphQL Signature

```graphql theme={null}
mutation SetRoomState($id: ID!, $state: RoomState!) {
  setRoomState(id: $id, state: $state) {
    id
    state
    name
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  객실 ID
</ParamField>

<ParamField path="state" type="RoomState!" required>
  변경할 객실 상태: - `NOT_USING`: 미사용 - `USING`: 사용중 - `LEFT`: 퇴실 -
  `SELECTED`: 선택됨 - `POWER_DOWN`: 전원 차단
</ParamField>

#### 권한

* 숙박시설 스태프(STAFF) 이상 권한 필요

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    setRoomState(id: "01HQKS9V8X2N3P4Q5R6S7T8U9X", state: USING) {
      id
      state
      name
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "setRoomState": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9X",
        "state": "USING",
        "name": "101호"
      }
    }
  }
  ```
</CodeGroup>

***

### setRoomCleanState

객실 청소 상태를 변경합니다.

#### GraphQL Signature

```graphql theme={null}
mutation SetRoomCleanState($id: ID!, $cleanState: CleanState!) {
  setRoomCleanState(id: $id, cleanState: $cleanState) {
    id
    cleanState
    name
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  객실 ID
</ParamField>

<ParamField path="cleanState" type="CleanState!" required>
  변경할 청소 상태: - `CLEAN`: 청소 완료 - `DIRTY`: 청소 필요 - `CLEANING`:
  청소중 - `NEED_CLEANING`: 청소 요망 - `URGENT_CLEANING`: 긴급 청소 필요 -
  `INSPECTION`: 점검중 - `NEED_INSPECTION`: 점검 필요
</ParamField>

#### 권한

* 숙박시설 스태프(STAFF) 이상 권한 필요

***

### setRoomStateByStaff

스태프가 청소 상태를 단계적으로 진행합니다 (DIRTY → CLEANING → CLEAN).

#### GraphQL Signature

```graphql theme={null}
mutation SetRoomStateByStaff($id: ID!) {
  setRoomStateByStaff(id: $id) {
    id
    cleanState
    name
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  객실 ID
</ParamField>

#### 동작

* `DIRTY` → `CLEANING`: 청소 시작
* `CLEANING` → `CLEAN`: 청소 완료
* 기타 상태에서는 오류 발생

#### 권한

* 숙박시설 메이드(MAID) 이상 권한 필요

***

### assignRoomRequest

예약에 대해 사용 가능한 객실을 자동으로 배정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation AssignRoomRequest(
  $roomTypeId: ID!
  $orderBy: String!
  $reservationType: String
  $useStartAt: DateTime!
  $useExpireAt: DateTime!
  $reservationId: ID!
) {
  assignRoomRequest(
    roomTypeId: $roomTypeId
    orderBy: $orderBy
    reservationType: $reservationType
    useStartAt: $useStartAt
    useExpireAt: $useExpireAt
    reservationId: $reservationId
  ) {
    id
    name
    roomTypeId
  }
}
```

#### 파라미터

<ParamField path="roomTypeId" type="ID!" required>
  배정할 객실 타입 ID
</ParamField>

<ParamField path="orderBy" type="String!" required>
  객실 선택 방식: - `priority`: 우선순위 높은 객실 우선 - `random`: 무작위 선택

  * `updatedAt`: 가장 오래 업데이트되지 않은 객실 우선
</ParamField>

<ParamField path="reservationType" type="String">
  예약 타입 (`rental` 또는 `stay`)
</ParamField>

<ParamField path="useStartAt" type="DateTime!" required>
  사용 시작 일시
</ParamField>

<ParamField path="useExpireAt" type="DateTime!" required>
  사용 종료 일시
</ParamField>

<ParamField path="reservationId" type="ID!" required>
  예약 ID
</ParamField>

#### 배정 조건

* 객실 상태: `NOT_USING`
* 청소 상태: `CLEAN`
* 판매 상태: `ALL` 또는 예약 타입에 맞는 상태
* 카드 상태: `guest`가 아님
* 해당 기간에 다른 예약 없음

#### 권한

* 관리자(ADMIN) 권한 필요

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    assignRoomRequest(
      roomTypeId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      orderBy: "priority"
      reservationType: "stay"
      useStartAt: "2025-12-23T15:00:00Z"
      useExpireAt: "2025-12-24T11:00:00Z"
      reservationId: "01HQKS9V8X2N3P4Q5R6S7T8U9W"
    ) {
      id
      name
      roomTypeId
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "assignRoomRequest": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9X",
        "name": "101호",
        "roomTypeId": "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      }
    }
  }
  ```
</CodeGroup>

#### 에러 처리

<ResponseField name="NO_AVAILABLE_ROOM">
  배정 가능한 객실이 없습니다.
</ResponseField>

<ResponseField name="INVALID_ORDER_BY_ASSIGN_REQUEST">
  유효하지 않은 orderBy 값입니다.
</ResponseField>

***

### createRoomOccupancyTimeline

객실 점유 타임라인을 생성합니다. 특정 기간 동안 객실의 점유 상태를 기록합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateRoomOccupancyTimeline(
  $input: CreateRoomOccupancyTimelineInput!
) {
  createRoomOccupancyTimeline(input: $input) {
    id
    roomId
    occupancyStatus
    startAt
    endAt
    note
  }
}
```

#### 파라미터

<ParamField path="input.roomId" type="ID!" required>
  객실 ID
</ParamField>

<ParamField path="input.occupancyStatus" type="OccupancyStatus!" required>
  점유 상태: - `OCCUPIED`: 점유됨 - `DISABLED`: 사용 중지
</ParamField>

<ParamField path="input.startAt" type="DateTime!" required>
  시작 일시
</ParamField>

<ParamField path="input.endAt" type="DateTime!" required>
  종료 일시
</ParamField>

<ParamField path="input.note" type="String">
  메모
</ParamField>

<ParamField path="input.isIncludedToQuantity" type="Boolean">
  재고 수량 포함 여부
</ParamField>

<ParamField path="input.reservationId" type="ID">
  연관된 예약 ID
</ParamField>

#### 제약사항

* `endAt`은 `startAt`보다 이후여야 함
* 동일 기간에 동일 상태의 타임라인 중복 불가

#### 권한

* 숙박시설 스태프(STAFF) 이상 권한 필요

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createRoomOccupancyTimeline(
      input: {
        roomId: "01HQKS9V8X2N3P4Q5R6S7T8U9X"
        occupancyStatus: DISABLED
        startAt: "2025-12-25T00:00:00Z"
        endAt: "2025-12-31T23:59:59Z"
        note: "보수 공사로 인한 운영 중단"
        isIncludedToQuantity: false
      }
    ) {
      id
      roomId
      occupancyStatus
      startAt
      endAt
      note
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createRoomOccupancyTimeline": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9Y",
        "roomId": "01HQKS9V8X2N3P4Q5R6S7T8U9X",
        "occupancyStatus": "DISABLED",
        "startAt": "2025-12-25T00:00:00Z",
        "endAt": "2025-12-31T23:59:59Z",
        "note": "보수 공사로 인한 운영 중단"
      }
    }
  }
  ```
</CodeGroup>

#### 에러 처리

<ResponseField name="INVALID_PARAMETER">
  종료 일시가 시작 일시보다 이전입니다.
</ResponseField>

<ResponseField name="ROOM_OCCUPANCY_TIMELINE_DUPLICATED">
  동일 기간에 중복된 타임라인이 존재합니다.
</ResponseField>

***

### updateRoomOccupancyTimeline

객실 점유 타임라인을 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateRoomOccupancyTimeline(
  $input: UpdateRoomOccupancyTimelineInput!
) {
  updateRoomOccupancyTimeline(input: $input) {
    id
    startAt
    endAt
    note
  }
}
```

#### 파라미터

<ParamField path="input.id" type="ID!" required>
  타임라인 ID
</ParamField>

<ParamField path="input.startAt" type="DateTime">
  시작 일시
</ParamField>

<ParamField path="input.endAt" type="DateTime">
  종료 일시
</ParamField>

<ParamField path="input.note" type="String">
  메모
</ParamField>

#### 권한

* 숙박시설 스태프(STAFF) 이상 권한 필요

***

### deleteRoomOccupancyTimeline

객실 점유 타임라인을 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteRoomOccupancyTimeline($id: ID!) {
  deleteRoomOccupancyTimeline(id: $id) {
    id
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  삭제할 타임라인 ID
</ParamField>

#### 권한

* 숙박시설 스태프(STAFF) 이상 권한 필요

***

### createPrice

객실 타입의 가격 정보를 생성합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreatePrice($input: CreatePriceInput!) {
  createPrice(input: $input) {
    id
    roomTypeId
    priceType
    priceTimes {
      startTime
      endTime
      price
      type
    }
  }
}
```

#### 파라미터

<ParamField path="input.roomTypeId" type="ID!" required>
  객실 타입 ID
</ParamField>

<ParamField path="input.priceType" type="String!" required>
  가격 타입 (예: `rental`, `stay`)
</ParamField>

<ParamField path="input.priceTimes" type="[PriceTimeInput]">
  시간대별 가격 정보: - `startTime`: 시작 시간 - `endTime`: 종료 시간 - `price`:
  가격 - `type`: 타입
</ParamField>

<ParamField path="input.ariPackageId" type="ID">
  연관된 ARI 패키지 ID
</ParamField>

#### 제약사항

* 동일한 타입의 시간대가 겹치면 안 됨
* 동일한 `priceType` 및 `ariPackageId` 조합 중복 불가

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요

#### 에러 처리

<ResponseField name="OVERLAPPING_PRICE_TIMES">
  시간대가 겹치는 가격 정보가 있습니다.
</ResponseField>

<ResponseField name="DUPLICATED_DATA_FOUND">
  동일한 가격 정보가 이미 존재합니다.
</ResponseField>

***

### updatePrice

가격 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdatePrice($input: UpdatePriceInput!) {
  updatePrice(input: $input) {
    id
    priceType
    priceTimes {
      startTime
      endTime
      price
    }
  }
}
```

#### 파라미터

<ParamField path="input.id" type="ID!" required>
  수정할 가격 ID
</ParamField>

<ParamField path="input.priceType" type="String">
  가격 타입
</ParamField>

<ParamField path="input.priceTimes" type="[PriceTimeInput]">
  시간대별 가격 정보
</ParamField>

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요

***

### deletePrice

가격 정보를 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeletePrice($id: ID!) {
  deletePrice(id: $id) {
    result
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  삭제할 가격 ID
</ParamField>

#### 권한

* 숙박시설 관리자(MANAGER) 권한 필요

***

### Room Memo 관리

#### createRoomMemo

객실 메모를 생성합니다.

```graphql theme={null}
mutation CreateRoomMemo($input: CreateRoomMemoInput!) {
  createRoomMemo(input: $input) {
    id
    roomId
    type
    content
  }
}
```

#### updateRoomMemo

객실 메모를 수정합니다.

```graphql theme={null}
mutation UpdateRoomMemo($input: UpdateRoomMemoInput!) {
  updateRoomMemo(input: $input) {
    id
    type
    content
  }
}
```

#### setRoomMemo

객실 메모를 생성하거나 수정합니다 (upsert).

```graphql theme={null}
mutation SetRoomMemo($input: SetRoomMemoInput!) {
  setRoomMemo(input: $input) {
    id
    roomId
    type
    content
  }
}
```

#### deleteRoomMemo

객실 메모를 삭제합니다.

```graphql theme={null}
mutation DeleteRoomMemo($id: ID!) {
  deleteRoomMemo(id: $id) {
    result
  }
}
```

**권한**: 숙박시설 스태프(STAFF) 이상 권한 필요

***

### Room Device 관리

#### createRoomDevice

객실 디바이스를 생성합니다.

```graphql theme={null}
mutation CreateRoomDevice($roomId: ID!, $input: CreateRoomDeviceInput!) {
  createRoomDevice(roomId: $roomId, input: $input) {
    id
    name
    type
    state
    power
  }
}
```

#### updateRoomDevice

객실 디바이스를 수정합니다.

```graphql theme={null}
mutation UpdateRoomDevice($id: ID!, $input: UpdateRoomDeviceInput!) {
  updateRoomDevice(id: $id, input: $input) {
    id
    name
    type
    state
    power
  }
}
```

#### bulkUpdateRoomDevice

여러 객실 디바이스를 일괄 수정합니다.

```graphql theme={null}
mutation BulkUpdateRoomDevice($ids: [ID!]!, $input: UpdateRoomDeviceInput!) {
  bulkUpdateRoomDevice(ids: $ids, input: $input) {
    id
    name
    state
  }
}
```

#### deleteRoomDevice

객실 디바이스를 삭제합니다.

```graphql theme={null}
mutation DeleteRoomDevice($id: ID!) {
  deleteRoomDevice(id: $id) {
    result
  }
}
```

**권한**: 숙박시설 관리자(MANAGER) 권한 필요

***

## 객실 상태 흐름

### 기본 객실 상태 (RoomState)

```mermaid theme={null}
graph LR
    A[NOT_USING] -->|예약 배정| B[SELECTED]
    B -->|체크인| C[USING]
    C -->|체크아웃| D[LEFT]
    D -->|청소 완료| A
    A -->|전원 차단| E[POWER_DOWN]
    E -->|전원 복구| A
```

### 청소 상태 (CleanState)

```mermaid theme={null}
graph LR
    A[DIRTY] -->|청소 시작| B[CLEANING]
    B -->|청소 완료| C[CLEAN]
    C -->|사용 후| A
    A -->|긴급| D[URGENT_CLEANING]
    D -->|청소 시작| B
    C -->|점검 필요| E[NEED_INSPECTION]
    E -->|점검 시작| F[INSPECTION]
    F -->|점검 완료| C
```

### 복합 상태 (CalculatedState)

`calculatedState`는 다음 정보를 종합하여 계산됩니다:

* 객실 상태 (`state`)
* 청소 상태 (`cleanState`)
* 카드 상태 (`cardState`)
* 예약 정보 (`currentReservation`, `upcomingReservation`)
* 점유 타임라인 (`roomOccupancyTimeline`)

#### 주요 복합 상태

* `available`: 판매 가능 (청소 완료, 사용 가능)
* `availableDirty`: 판매 가능하나 청소 필요
* `cleaning`: 청소중
* `needCleaning`: 청소 필요
* `urgentCleaning`: 긴급 청소 필요
* `inspection`: 점검중
* `needInspection`: 점검 필요
* `usingRental`: 대실 사용중
* `usingStay`: 숙박 사용중
* `leftRental`: 대실 퇴실
* `leftStay`: 숙박 퇴실
* `reservedRental`: 대실 예약
* `reservedStay`: 숙박 예약
* `expired`: 예약 만료
* `expiredEst`: 예약 만료 추정
* `usingExpired`: 사용중 (예약 만료)
* `usingUnknown`: 사용중 (예약 정보 없음)
* `disabled`: 판매 중지
* `disabledSuspicious`: 판매 중지 (카드 감지됨)
* `powerDown`: 전원 차단
* `selected`: 선택됨
* `unknown`: 알 수 없음

***

## 객실 타임라인

### OccupancyStatus

객실 점유 타임라인의 상태:

* `OCCUPIED`: 예약으로 인한 점유
* `DISABLED`: 관리자가 설정한 사용 중지 기간

### 타임라인 사용 사례

1. **예약 점유**: 예약 생성 시 자동으로 `OCCUPIED` 타임라인 생성
2. **판매 중지**: 보수 공사, 시설 점검 등으로 `DISABLED` 타임라인 생성
3. **재고 관리**: `isIncludedToQuantity` 플래그로 판매 재고 수량 제어

***

## 관련 API

* [예약 API](/api-reference/core-svc/reservation) - 객실 예약 및 배정
* [재고 API](/api-reference/core-svc/inventory) - 객실 타입별 재고 관리
* [가격 API](/api-reference/core-svc/price) - 객실 타입 가격 정책
