> ## 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.

# 프로필 관리 (Profile)

> 고객 프로필 및 관련 정보 관리 API

## 개요

Core 서비스의 프로필 도메인은 숙박 고객의 정보를 체계적으로 관리합니다. 프로필 기본 정보, 신원 정보, 연락처, 외부 코드, 차량 정보 및 프로필 간 관계를 종합적으로 제공합니다.

### 주요 기능

* **프로필 관리**: 개인/단체 프로필 생성, 수정, 삭제, 병합
* **신원 정보**: 여권, 국민등록번호 등 신원 문서 관리
* **연락처**: 전화번호, 이메일 등 연락처 정보 관리
* **외부 코드**: OTA 플랫폼 등 외부 시스템 연동 코드
* **차량 정보**: 고객 차량번호 등록 및 관리
* **프로필 관계**: 그룹 멤버십, 가족 관계 등 프로필 간 관계

## Queries

### profile

특정 프로필의 상세 정보를 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetProfile($id: ID!) {
  profile(id: $id) {
    id
    accommodationId
    type
    name
    displayName
    birthDate
    gender
    status
    source
    metadata
    createdAt
    updatedAt

    # 연관 정보
    identities {
      id
      identityType
      identityNumber
      country
    }
    contacts {
      id
      contactType
      contactValue
      isPrimary
    }
    codes {
      id
      platform
      externalCode
    }
    vehicles {
      id
      vehicleNumber
      vehicleType
    }

    # 하위 호환 필드
    phone
    email
    passportNumber
    country
    vehicleNumbers
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  조회할 프로필 ID (ULID 형식)
</ParamField>

#### 응답 필드

<ResponseField name="id" type="ID!">
  프로필 고유 식별자
</ResponseField>

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

<ResponseField name="type" type="ProfileType!">
  프로필 타입:

  * `INDIVIDUAL`: 개인
  * `GROUP`: 단체
</ResponseField>

<ResponseField name="name" type="String!">
  프로필 이름 (법적 이름)
</ResponseField>

<ResponseField name="displayName" type="String">
  표시용 이름 (선호 이름)
</ResponseField>

<ResponseField name="birthDate" type="Date">
  생년월일
</ResponseField>

<ResponseField name="gender" type="Gender">
  성별: `MALE`, `FEMALE`, `OTHER`
</ResponseField>

<ResponseField name="status" type="ProfileStatus!">
  프로필 상태:

  * `ACTIVE`: 활성
  * `INACTIVE`: 비활성
  * `BLOCKED`: 차단됨
</ResponseField>

<ResponseField name="identities" type="[ProfileIdentity!]!">
  신원 정보 목록 (여권, 신분증 등)
</ResponseField>

<ResponseField name="contacts" type="[ProfileContact!]!">
  연락처 정보 목록
</ResponseField>

<ResponseField name="codes" type="[ProfileCode!]!">
  외부 시스템 코드 목록
</ResponseField>

<ResponseField name="vehicles" type="[ProfileVehicle!]!">
  차량 정보 목록
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  query {
    profile(id: "01HQKS9V8X2N3P4Q5R6S7T8U9V") {
      id
      name
      displayName
      birthDate
      gender
      contacts {
        contactType
        contactValue
        isPrimary
      }
      identities {
        identityType
        identityNumber
        country
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "profile": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9V",
        "name": "홍길동",
        "displayName": "길동",
        "birthDate": "1990-01-15",
        "gender": "MALE",
        "contacts": [
          {
            "contactType": "PHONE",
            "contactValue": "01012345678",
            "isPrimary": true
          },
          {
            "contactType": "EMAIL",
            "contactValue": "hong@example.com",
            "isPrimary": true
          }
        ],
        "identities": [
          {
            "identityType": "PASSPORT",
            "identityNumber": "M12345678",
            "country": "KR"
          }
        ]
      }
    }
  }
  ```
</CodeGroup>

***

### profiles

프로필 목록을 필터링하여 페이지네이션 방식으로 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetProfiles(
  $filter: ProfileFilterInput
  $orders: [OrderInput!]
  $pagination: PaginationInput
) {
  profiles(filter: $filter, orders: $orders, pagination: $pagination) {
    items {
      id
      name
      displayName
      type
      status
      createdAt
    }
    totalCount
    pageInfo {
      hasNextPage
      hasPreviousPage
    }
  }
}
```

#### 파라미터

<ParamField path="filter" type="ProfileFilterInput">
  프로필 필터 조건:

  * `accommodationId`: 숙박시설 ID
  * `type`: 프로필 타입 (`INDIVIDUAL`, `GROUP`)
  * `status`: 프로필 상태
  * `source`: 프로필 생성 출처
  * `name`: 이름 검색 (부분 일치)
  * `startDate`: 생성일 시작 범위
  * `endDate`: 생성일 종료 범위
  * `groupProfileIds`: 특정 그룹의 멤버만 조회
</ParamField>

<ParamField path="orders" type="[OrderInput!]">
  정렬 기준 배열
</ParamField>

<ParamField path="pagination" type="PaginationInput">
  페이지네이션 옵션
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  query {
    profiles(
      filter: {
        accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
        type: INDIVIDUAL
        status: ACTIVE
      }
      pagination: {
        limit: 20
        offset: 0
      }
      orders: [{ field: "createdAt", direction: DESC }]
    ) {
      items {
        id
        name
        phone
        email
        createdAt
      }
      totalCount
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "profiles": {
        "items": [
          {
            "id": "01HQKS9V8X2N3P4Q5R6S7T8U9V",
            "name": "홍길동",
            "phone": "01012345678",
            "email": "hong@example.com",
            "createdAt": "2024-01-15T10:30:00Z"
          }
        ],
        "totalCount": 1
      }
    }
  }
  ```
</CodeGroup>

## Mutations

### createProfile

새로운 프로필을 생성합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateProfile($input: CreateProfileInput!) {
  createProfile(input: $input) {
    id
    name
    displayName
    type
    status
    createdAt
  }
}
```

#### 파라미터

<ParamField path="input" type="CreateProfileInput!" required>
  프로필 생성 정보:

  * `accommodationId`: 숙박시설 ID (필수)
  * `type`: 프로필 타입 (필수)
  * `name`: 이름 (필수)
  * `displayName`: 표시 이름
  * `birthDate`: 생년월일
  * `gender`: 성별
  * `metadata`: 추가 메타데이터
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createProfile(input: {
      accommodationId: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
      type: INDIVIDUAL
      name: "김철수"
      displayName: "철수"
      birthDate: "1985-03-20"
      gender: MALE
    }) {
      id
      name
      displayName
      status
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createProfile": {
        "id": "01HQKT1A2B3C4D5E6F7G8H9J0K",
        "name": "김철수",
        "displayName": "철수",
        "status": "ACTIVE"
      }
    }
  }
  ```
</CodeGroup>

***

### updateProfile

기존 프로필 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateProfile($id: ID!, $input: UpdateProfileInput!) {
  updateProfile(id: $id, input: $input) {
    id
    name
    displayName
    status
    updatedAt
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  수정할 프로필 ID
</ParamField>

<ParamField path="input" type="UpdateProfileInput!" required>
  수정할 필드 (선택적으로 제공):

  * `name`: 이름
  * `displayName`: 표시 이름
  * `birthDate`: 생년월일
  * `gender`: 성별
  * `status`: 상태
  * `metadata`: 메타데이터
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    updateProfile(
      id: "01HQKT1A2B3C4D5E6F7G8H9J0K"
      input: {
        displayName: "철수님"
        status: ACTIVE
      }
    ) {
      id
      displayName
      status
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "updateProfile": {
        "id": "01HQKT1A2B3C4D5E6F7G8H9J0K",
        "displayName": "철수님",
        "status": "ACTIVE"
      }
    }
  }
  ```
</CodeGroup>

***

### deleteProfile

프로필을 삭제합니다 (소프트 삭제).

#### GraphQL Signature

```graphql theme={null}
mutation DeleteProfile($id: ID!) {
  deleteProfile(id: $id)
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  삭제할 프로필 ID
</ParamField>

#### 응답

<ResponseField name="success" type="Boolean!">
  삭제 성공 여부 (항상 true)
</ResponseField>

***

### mergeProfiles

두 개의 프로필을 병합합니다. 보조 프로필의 모든 정보가 주 프로필로 통합됩니다.

#### GraphQL Signature

```graphql theme={null}
mutation MergeProfiles($primaryId: ID!, $secondaryId: ID!) {
  mergeProfiles(primaryId: $primaryId, secondaryId: $secondaryId) {
    id
    name
    identities {
      id
      identityType
    }
    contacts {
      id
      contactType
    }
  }
}
```

#### 파라미터

<ParamField path="primaryId" type="ID!" required>
  주 프로필 ID (병합 후 유지될 프로필)
</ParamField>

<ParamField path="secondaryId" type="ID!" required>
  보조 프로필 ID (병합 후 삭제될 프로필)
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    mergeProfiles(
      primaryId: "01HQKT1A2B3C4D5E6F7G8H9J0K"
      secondaryId: "01HQKT2B3C4D5E6F7G8H9J0K1L"
    ) {
      id
      name
      contacts {
        contactType
        contactValue
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "mergeProfiles": {
        "id": "01HQKT1A2B3C4D5E6F7G8H9J0K",
        "name": "김철수",
        "contacts": [
          {
            "contactType": "PHONE",
            "contactValue": "01012345678"
          },
          {
            "contactType": "EMAIL",
            "contactValue": "kim@example.com"
          }
        ]
      }
    }
  }
  ```
</CodeGroup>

***

## ProfileIdentity 관리

### createProfileIdentity

프로필에 신원 정보를 추가합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateProfileIdentity($input: CreateProfileIdentityInput!) {
  createProfileIdentity(input: $input) {
    id
    identityType
    identityNumber
    country
    issueDate
    expiryDate
  }
}
```

#### 파라미터

<ParamField path="input" type="CreateProfileIdentityInput!" required>
  신원 정보:

  * `profileId`: 프로필 ID (필수)
  * `identityType`: 신원 유형 (필수) - `PASSPORT`, `NATIONAL_ID`, `DRIVER_LICENSE` 등
  * `identityNumber`: 신원 번호 (필수)
  * `country`: 국가 코드
  * `issueDate`: 발급일
  * `expiryDate`: 만료일
  * `status`: 상태
  * `metadata`: 추가 정보
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createProfileIdentity(input: {
      profileId: "01HQKT1A2B3C4D5E6F7G8H9J0K"
      identityType: PASSPORT
      identityNumber: "M12345678"
      country: "KR"
      issueDate: "2020-01-01"
      expiryDate: "2030-01-01"
      status: ACTIVE
    }) {
      id
      identityType
      identityNumber
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createProfileIdentity": {
        "id": "01HQKT3C4D5E6F7G8H9J0K1L2M",
        "identityType": "PASSPORT",
        "identityNumber": "M12345678"
      }
    }
  }
  ```
</CodeGroup>

***

### updateProfileIdentity

기존 신원 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateProfileIdentity($id: ID!, $input: UpdateProfileIdentityInput!) {
  updateProfileIdentity(id: $id, input: $input) {
    id
    identityType
    identityNumber
    expiryDate
  }
}
```

***

### deleteProfileIdentity

신원 정보를 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteProfileIdentity($id: ID!) {
  deleteProfileIdentity(id: $id)
}
```

***

## ProfileContact 관리

### createProfileContact

프로필에 연락처 정보를 추가합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateProfileContact($input: CreateProfileContactInput!) {
  createProfileContact(input: $input) {
    id
    contactType
    contactValue
    isPrimary
    status
  }
}
```

#### 파라미터

<ParamField path="input" type="CreateProfileContactInput!" required>
  연락처 정보:

  * `profileId`: 프로필 ID (필수)
  * `contactType`: 연락처 유형 (필수) - `PHONE`, `EMAIL`, `ADDRESS` 등
  * `contactValue`: 연락처 값 (필수)
  * `isPrimary`: 주 연락처 여부
  * `status`: 상태
  * `metadata`: 추가 정보
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createProfileContact(input: {
      profileId: "01HQKT1A2B3C4D5E6F7G8H9J0K"
      contactType: PHONE
      contactValue: "01012345678"
      isPrimary: true
      status: ACTIVE
    }) {
      id
      contactType
      contactValue
      isPrimary
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createProfileContact": {
        "id": "01HQKT4D5E6F7G8H9J0K1L2M3N",
        "contactType": "PHONE",
        "contactValue": "01012345678",
        "isPrimary": true
      }
    }
  }
  ```
</CodeGroup>

***

### updateProfileContact

기존 연락처 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateProfileContact($id: ID!, $input: UpdateProfileContactInput!) {
  updateProfileContact(id: $id, input: $input) {
    id
    contactValue
    isPrimary
  }
}
```

***

### deleteProfileContact

연락처 정보를 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteProfileContact($id: ID!) {
  deleteProfileContact(id: $id)
}
```

***

### setPrimaryContact

특정 연락처를 주 연락처로 설정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation SetPrimaryContact($id: ID!) {
  setPrimaryContact(id: $id) {
    id
    contactType
    isPrimary
  }
}
```

***

## ProfileCode 관리

### createProfileCode

외부 플랫폼 코드를 프로필에 추가합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateProfileCode($input: CreateProfileCodeInput!) {
  createProfileCode(input: $input) {
    id
    platform
    externalCode
    status
  }
}
```

#### 파라미터

<ParamField path="input" type="CreateProfileCodeInput!" required>
  외부 코드 정보:

  * `profileId`: 프로필 ID (필수)
  * `platform`: 플랫폼 이름 (필수)
  * `externalCode`: 외부 시스템 코드 (필수)
  * `status`: 상태
  * `metadata`: 추가 정보
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createProfileCode(input: {
      profileId: "01HQKT1A2B3C4D5E6F7G8H9J0K"
      platform: "Booking.com"
      externalCode: "GUEST123456"
      status: ACTIVE
    }) {
      id
      platform
      externalCode
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createProfileCode": {
        "id": "01HQKT5E6F7G8H9J0K1L2M3N4P",
        "platform": "Booking.com",
        "externalCode": "GUEST123456"
      }
    }
  }
  ```
</CodeGroup>

***

### updateProfileCode

외부 코드 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateProfileCode($id: ID!, $input: UpdateProfileCodeInput!) {
  updateProfileCode(id: $id, input: $input) {
    id
    platform
    externalCode
  }
}
```

***

### deleteProfileCode

외부 코드를 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteProfileCode($id: ID!) {
  deleteProfileCode(id: $id)
}
```

***

## ProfileVehicle 관리

### createProfileVehicle

프로필에 차량 정보를 추가합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateProfileVehicle($input: CreateProfileVehicleInput!) {
  createProfileVehicle(input: $input) {
    id
    vehicleNumber
    vehicleType
    status
  }
}
```

#### 파라미터

<ParamField path="input" type="CreateProfileVehicleInput!" required>
  차량 정보:

  * `profileId`: 프로필 ID (필수)
  * `vehicleNumber`: 차량번호 (필수)
  * `vehicleType`: 차량 유형
  * `status`: 상태
  * `metadata`: 추가 정보
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createProfileVehicle(input: {
      profileId: "01HQKT1A2B3C4D5E6F7G8H9J0K"
      vehicleNumber: "12가3456"
      vehicleType: "SEDAN"
      status: ACTIVE
    }) {
      id
      vehicleNumber
      vehicleType
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createProfileVehicle": {
        "id": "01HQKT6F7G8H9J0K1L2M3N4P5Q",
        "vehicleNumber": "12가3456",
        "vehicleType": "SEDAN"
      }
    }
  }
  ```
</CodeGroup>

***

### updateProfileVehicle

차량 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateProfileVehicle($id: ID!, $input: UpdateProfileVehicleInput!) {
  updateProfileVehicle(id: $id, input: $input) {
    id
    vehicleNumber
    vehicleType
  }
}
```

***

### deleteProfileVehicle

차량 정보를 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteProfileVehicle($id: ID!) {
  deleteProfileVehicle(id: $id)
}
```

***

## ProfileRelation 관리

### createProfileRelation

두 프로필 간의 관계를 생성합니다.

#### GraphQL Signature

```graphql theme={null}
mutation CreateProfileRelation($input: CreateProfileRelationInput!) {
  createProfileRelation(input: $input) {
    id
    relationType
    fromProfile {
      id
      name
    }
    toProfile {
      id
      name
    }
  }
}
```

#### 파라미터

<ParamField path="input" type="CreateProfileRelationInput!" required>
  관계 정보:

  * `fromProfileId`: 출발 프로필 ID (필수)
  * `toProfileId`: 도착 프로필 ID (필수)
  * `relationType`: 관계 유형 (필수) - `MEMBER_OF`, `FAMILY`, `SPOUSE` 등
  * `metadata`: 추가 정보
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    createProfileRelation(input: {
      fromProfileId: "01HQKT1A2B3C4D5E6F7G8H9J0K"
      toProfileId: "01HQKT2B3C4D5E6F7G8H9J0K1L"
      relationType: MEMBER_OF
    }) {
      id
      relationType
      fromProfile {
        name
      }
      toProfile {
        name
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "createProfileRelation": {
        "id": "01HQKT7G8H9J0K1L2M3N4P5Q6R",
        "relationType": "MEMBER_OF",
        "fromProfile": {
          "name": "김철수"
        },
        "toProfile": {
          "name": "단체A"
        }
      }
    }
  }
  ```
</CodeGroup>

***

### updateProfileRelation

프로필 관계 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateProfileRelation($id: ID!, $input: UpdateProfileRelationInput!) {
  updateProfileRelation(id: $id, input: $input) {
    id
    relationType
  }
}
```

***

### deleteProfileRelation

프로필 간 관계를 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteProfileRelation($id: ID!) {
  deleteProfileRelation(id: $id)
}
```

***

## 프라이버시 보호

프로필 도메인의 민감한 정보는 GraphQL 스키마의 `@mask` 디렉티브를 통해 자동으로 마스킹됩니다:

* **전화번호**: 중간 4자리 마스킹 (010-\*\*\*\*-5678)
* **이메일**: 일부 문자 마스킹 (h\*\*\*@example.com)
* **신원번호**: 일부 숫자 마스킹

접근 권한이 있는 사용자만 완전한 정보를 조회할 수 있습니다.

## 관련 API

* [예약 API](/api-reference/core-svc/reservation) - 프로필 기반 예약 관리
* [채널 API](/api-reference/core-svc/channel) - OTA 채널 연동
