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

# 사용자 (User)

> 사용자 관리 및 프로필 API

## 개요

User 도메인은 사용자 계정 관리, 프로필 수정, 직원 관리, 연락처 관리 등의 기능을 제공합니다.

## Types

### UserType (Enum)

사용자 권한 레벨을 정의합니다.

* `CUSTOMER`: 일반 고객
* `PARTNER`: 파트너
* `PARTNERADMIN`: 파트너 관리자
* `ADMIN`: 관리자
* `SUPERADMIN`: 최고 관리자

### DuplicateCheckerType (Enum)

중복 확인 필드 타입을 정의합니다.

* `identity`: 아이디
* `email`: 이메일
* `phone`: 휴대폰 번호
* `nickname`: 닉네임

## Queries

### getUsers

사용자 목록을 페이지네이션으로 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetUsers($first: Int, $last: Int, $filter: UsersFilter) {
  getUsers(first: $first, last: $last, filter: $filter) {
    edges {
      cursor
      node {
        id
        identity
        phone
        name
        nickname
        email
        accessLevel
        isAuthorizedEmail
        isAuthorizedPhone
      }
    }
    pageInfo {
      hasNextPage
      hasPreviousPage
      startCursor
      endCursor
    }
    totalCount
  }
}
```

#### 파라미터

<ParamField path="first" type="Int">
  처음부터 가져올 개수
</ParamField>

<ParamField path="last" type="Int">
  끝에서부터 가져올 개수
</ParamField>

<ParamField path="filter.keyword" type="String">
  검색 키워드 (이름, 이메일, 아이디 등)
</ParamField>

#### 응답

<ResponseField name="edges" type="[UserEdge!]!">
  사용자 목록

  <Expandable title="UserEdge">
    <ResponseField name="cursor" type="String!">
      페이지네이션 커서
    </ResponseField>

    <ResponseField name="node" type="User">
      사용자 정보
    </ResponseField>
  </Expandable>
</ResponseField>

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

<ResponseField name="totalCount" type="Int!">
  전체 사용자 수
</ResponseField>

***

### findUser

특정 사용자의 상세 정보를 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query FindUser($id: ID!) {
  findUser(id: $id) {
    id
    identity
    phone
    name
    nickname
    email
    accessLevel
    isAuthorizedEmail
    isAuthorizedPhone
  }
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  사용자 ID
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  query {
    findUser(id: "01HQKS9V8X2N3P4Q5R6S7T8U9V") {
      id
      name
      email
      accessLevel
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "findUser": {
        "id": "01HQKS9V8X2N3P4Q5R6S7T8U9V",
        "name": "홍길동",
        "email": "hong@example.com",
        "accessLevel": "CUSTOMER"
      }
    }
  }
  ```
</CodeGroup>

***

### myInfo

현재 로그인한 사용자의 정보를 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query MyInfo {
  myInfo {
    id
    identity
    phone
    name
    nickname
    email
    accessLevel
    isAuthorizedEmail
    isAuthorizedPhone
  }
}
```

#### 응답

<ResponseField name="User" type="User">
  현재 사용자 정보
</ResponseField>

<Info>
  이 API는 인증이 필요하며, JWT 토큰에서 사용자 정보를 추출합니다.
</Info>

***

### myContacts

현재 로그인한 사용자의 연락처 목록을 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query MyContacts($type: String) {
  myContacts(type: $type) {
    id
    userId
    type
    contact
  }
}
```

#### 파라미터

<ParamField path="type" type="String">
  연락처 타입 필터 (예: "email", "phone", "kakao")
</ParamField>

***

### getAccommodationContacts

특정 숙박 시설의 직원 연락처 목록을 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetAccommodationContacts(
  $accommodationId: ID!
  $type: String
  $authority: AccommodationAuthority
) {
  getAccommodationContacts(
    accommodationId: $accommodationId
    type: $type
    authority: $authority
  ) {
    id
    userId
    type
    contact
  }
}
```

#### 파라미터

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

<ParamField path="type" type="String">
  연락처 타입 필터
</ParamField>

<ParamField path="authority" type="String">
  권한 필터
</ParamField>

***

### verifyDuplicate

회원가입 시 아이디, 이메일, 닉네임 중복을 확인합니다.

#### GraphQL Signature

```graphql theme={null}
query VerifyDuplicate($input: VerifyDuplicateInput!) {
  verifyDuplicate(input: $input) {
    id
    verified
    error
  }
}
```

#### 파라미터

<ParamField path="input.identity" type="String">
  확인할 아이디
</ParamField>

<ParamField path="input.email" type="String">
  확인할 이메일
</ParamField>

<ParamField path="input.nickname" type="String">
  확인할 닉네임
</ParamField>

#### 응답

<ResponseField name="id" type="ID!">
  확인 ID
</ResponseField>

<ResponseField name="verified" type="Boolean!">
  중복 여부 (true: 사용 가능, false: 중복됨)
</ResponseField>

<ResponseField name="error" type="[DuplicateCheckerType]">
  중복된 필드 목록
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  query {
    verifyDuplicate(input: {
      identity: "testuser"
      email: "test@example.com"
      nickname: "테스터"
    }) {
      verified
      error
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "verifyDuplicate": {
        "verified": false,
        "error": ["email"]
      }
    }
  }
  ```
</CodeGroup>

***

### getPermanentToken

키오스크용 영구 토큰을 발급받습니다.

#### GraphQL Signature

```graphql theme={null}
query GetPermanentToken($kioskId: ID!) {
  getPermanentToken(kioskId: $kioskId)
}
```

#### 파라미터

<ParamField path="kioskId" type="ID!" required>
  키오스크 ID
</ParamField>

#### 응답

<ResponseField name="token" type="String">
  영구 토큰
</ResponseField>

***

### getPermanentTokenForAdmin

숙박 시설 관리자용 영구 토큰을 발급받습니다.

#### GraphQL Signature

```graphql theme={null}
query GetPermanentTokenForAdmin($accommodationId: ID!) {
  getPermanentTokenForAdmin(accommodationId: $accommodationId)
}
```

#### 파라미터

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

***

### getUserLogs

사용자 활동 로그를 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetUserLogs(
  $accommodationId: ID!
  $userId: ID
  $relatedId: ID
  $first: Int
  $last: Int
  $after: String
  $before: String
) {
  getUserLogs(
    accommodationId: $accommodationId
    userId: $userId
    relatedId: $relatedId
    first: $first
    last: $last
    after: $after
    before: $before
  ) {
    edges {
      cursor
      node {
        id
        user {
          id
          name
        }
        type
        log
        data
        createdAt
      }
    }
    pageInfo {
      hasNextPage
      hasPreviousPage
      startCursor
      endCursor
    }
    totalCount
  }
}
```

#### 파라미터

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

<ParamField path="userId" type="ID">
  특정 사용자의 로그만 조회
</ParamField>

<ParamField path="relatedId" type="ID">
  관련 엔티티 ID (예: 예약 ID)
</ParamField>

<ParamField path="first" type="Int">
  처음부터 가져올 개수
</ParamField>

<ParamField path="after" type="String">
  이 커서 이후의 로그
</ParamField>

***

### getMyAgreement

특정 약관에 대한 현재 사용자의 동의 여부를 조회합니다.

#### GraphQL Signature

```graphql theme={null}
query GetMyAgreement($type: String!) {
  getMyAgreement(type: $type)
}
```

#### 파라미터

<ParamField path="type" type="String!" required>
  약관 타입 (예: "privacy", "terms", "marketing")
</ParamField>

#### 응답

<ResponseField name="agreed" type="Boolean!">
  동의 여부
</ResponseField>

***

## Mutations

### signUp

새로운 사용자 계정을 생성합니다.

#### GraphQL Signature

```graphql theme={null}
mutation SignUp($input: SignUpInput!) {
  signUp(input: $input) {
    user {
      id
      identity
      name
      email
    }
  }
}
```

#### 파라미터

<ParamField path="input.identity" type="String!" required>
  사용자 아이디
</ParamField>

<ParamField path="input.phone" type="String">
  휴대폰 번호
</ParamField>

<ParamField path="input.accessLevel" type="UserType">
  사용자 권한 레벨 (기본값: CUSTOMER)
</ParamField>

<ParamField path="input.smsAuthHash" type="String">
  SMS 인증 해시 (휴대폰 번호 입력 시 필수)
</ParamField>

<ParamField path="input.name" type="String!" required>
  사용자 이름
</ParamField>

<ParamField path="input.nickname" type="String!" required>
  사용자 닉네임
</ParamField>

<ParamField path="input.email" type="String!" required>
  이메일 주소
</ParamField>

<ParamField path="input.password" type="String!" required>
  비밀번호
</ParamField>

#### 응답

<ResponseField name="user" type="User">
  생성된 사용자 정보
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    signUp(input: {
      identity: "testuser"
      name: "홍길동"
      nickname: "테스터"
      email: "test@example.com"
      password: "password123!"
      phone: "01012345678"
      smsAuthHash: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
    }) {
      user {
        id
        identity
        name
        email
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "signUp": {
        "user": {
          "id": "01HQKS9V8X2N3P4Q5R6S7T8U9V",
          "identity": "testuser",
          "name": "홍길동",
          "email": "test@example.com"
        }
      }
    }
  }
  ```
</CodeGroup>

<Info>
  휴대폰 번호를 입력하는 경우, 반드시 `requestSMSAuth` 및 `confirmSMSAuth`를 통해 발급받은 `smsAuthHash`를 제공해야 합니다.
</Info>

***

### signIn

사용자 로그인을 수행하고 인증 토큰을 발급받습니다.

#### GraphQL Signature

```graphql theme={null}
mutation SignIn($input: SignInInput!) {
  signIn(input: $input) {
    token {
      accessToken
      refreshToken
    }
  }
}
```

#### 파라미터

<ParamField path="input.identity" type="String!" required>
  사용자 아이디
</ParamField>

<ParamField path="input.password" type="String!" required>
  비밀번호
</ParamField>

#### 응답

<ResponseField name="token" type="TokenPayload">
  인증 토큰 정보

  <Expandable title="TokenPayload">
    <ResponseField name="accessToken" type="String!">
      액세스 토큰
    </ResponseField>

    <ResponseField name="refreshToken" type="String!">
      리프레시 토큰
    </ResponseField>
  </Expandable>
</ResponseField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    signIn(input: {
      identity: "testuser"
      password: "password123!"
    }) {
      token {
        accessToken
        refreshToken
      }
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "signIn": {
        "token": {
          "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
          "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
        }
      }
    }
  }
  ```
</CodeGroup>

***

### signInByAdmin

관리자가 다른 사용자로 로그인합니다.

#### GraphQL Signature

```graphql theme={null}
mutation SignInByAdmin($identity: String!) {
  signInByAdmin(identity: $identity) {
    token {
      accessToken
      refreshToken
    }
  }
}
```

#### 파라미터

<ParamField path="identity" type="String!" required>
  로그인할 사용자 아이디
</ParamField>

<Warning>
  이 API는 ADMIN 또는 SUPERADMIN 권한이 필요합니다.
</Warning>

***

### disableUser

사용자 계정을 비활성화하거나 활성화합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DisableUser($identity: String!, $disable: Boolean) {
  disableUser(identity: $identity, disable: $disable)
}
```

#### 파라미터

<ParamField path="identity" type="String!" required>
  대상 사용자 아이디
</ParamField>

<ParamField path="disable" type="Boolean">
  비활성화 여부 (true: 비활성화, false: 활성화)
</ParamField>

***

### addUserContact

사용자 연락처를 추가합니다.

#### GraphQL Signature

```graphql theme={null}
mutation AddUserContact($input: UserContactInput!) {
  addUserContact(input: $input) {
    id
    userId
    type
    contact
  }
}
```

#### 파라미터

<ParamField path="input.userId" type="ID!" required>
  사용자 ID
</ParamField>

<ParamField path="input.type" type="String!" required>
  연락처 타입 (예: "email", "phone", "kakao")
</ParamField>

<ParamField path="input.contact" type="String!" required>
  연락처 정보
</ParamField>

***

### modifyUserContact

사용자 연락처를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation ModifyUserContact($input: ModifyUserContactInput!) {
  modifyUserContact(input: $input) {
    id
    userId
    type
    contact
  }
}
```

#### 파라미터

<ParamField path="input.id" type="ID!" required>
  수정할 연락처 ID
</ParamField>

<ParamField path="input.type" type="String">
  새로운 연락처 타입
</ParamField>

<ParamField path="input.contact" type="String">
  새로운 연락처 정보
</ParamField>

***

### deleteUserContact

사용자 연락처를 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteUserContact($id: ID!) {
  deleteUserContact(id: $id)
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  삭제할 연락처 ID
</ParamField>

***

### updateInfo

현재 로그인한 사용자의 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateInfo($input: UserInput!) {
  updateInfo(input: $input) {
    id
    phone
    name
    nickname
    accessLevel
  }
}
```

#### 파라미터

<ParamField path="input.id" type="ID">
  사용자 ID (관리자가 다른 사용자 수정 시 사용)
</ParamField>

<ParamField path="input.phone" type="String">
  새로운 휴대폰 번호
</ParamField>

<ParamField path="input.smsAuthHash" type="String">
  SMS 인증 해시 (휴대폰 번호 변경 시 필수)
</ParamField>

<ParamField path="input.name" type="String">
  새로운 이름
</ParamField>

<ParamField path="input.nickname" type="String">
  새로운 닉네임
</ParamField>

<ParamField path="input.accessLevel" type="UserType">
  새로운 권한 레벨 (관리자만 가능)
</ParamField>

***

### updateEmployee

직원 정보를 수정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UpdateEmployee($input: EmployeeInput!) {
  updateEmployee(input: $input) {
    id
    name
    email
  }
}
```

#### 파라미터

<ParamField path="input.id" type="ID!" required>
  직원 ID
</ParamField>

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

<ParamField path="input.phone" type="String">
  새로운 휴대폰 번호
</ParamField>

<ParamField path="input.email" type="String">
  새로운 이메일
</ParamField>

<ParamField path="input.name" type="String">
  새로운 이름
</ParamField>

<ParamField path="input.nickname" type="String">
  새로운 닉네임
</ParamField>

<ParamField path="input.password" type="String">
  새로운 비밀번호
</ParamField>

<ParamField path="input.authority" type="String">
  새로운 권한
</ParamField>

***

### deleteEmployee

직원 계정을 삭제합니다.

#### GraphQL Signature

```graphql theme={null}
mutation DeleteEmployee($id: ID!) {
  deleteEmployee(id: $id)
}
```

#### 파라미터

<ParamField path="id" type="ID!" required>
  삭제할 직원 ID
</ParamField>

***

### changePassword

비밀번호를 변경합니다.

#### GraphQL Signature

```graphql theme={null}
mutation ChangePassword($input: ChangePasswordInput!) {
  changePassword(input: $input) {
    id
  }
}
```

#### 파라미터

<ParamField path="input.id" type="ID">
  사용자 ID (관리자가 다른 사용자의 비밀번호 변경 시 사용)
</ParamField>

<ParamField path="input.password" type="String!" required>
  새로운 비밀번호
</ParamField>

<ParamField path="input.currentPassword" type="String">
  현재 비밀번호 (본인의 비밀번호 변경 시 필수)
</ParamField>

***

### changePasswordBySMSAuth

SMS 인증을 통해 비밀번호를 재설정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation ChangePasswordBySMSAuth($input: ChangePasswordBySMSAuthInput!) {
  changePasswordBySMSAuth(input: $input)
}
```

#### 파라미터

<ParamField path="input.identity" type="String!" required>
  사용자 아이디
</ParamField>

<ParamField path="input.phone" type="String!" required>
  등록된 휴대폰 번호
</ParamField>

<ParamField path="input.password" type="String!" required>
  새로운 비밀번호
</ParamField>

<ParamField path="input.smsAuthHash" type="String!" required>
  SMS 인증 해시
</ParamField>

#### 예제

<CodeGroup>
  ```graphql Request theme={null}
  mutation {
    changePasswordBySMSAuth(input: {
      identity: "testuser"
      phone: "01012345678"
      password: "newpassword123!"
      smsAuthHash: "01HQKS9V8X2N3P4Q5R6S7T8U9V"
    })
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "changePasswordBySMSAuth": true
    }
  }
  ```
</CodeGroup>

***

### changePasswordByEmailAuth

이메일 인증을 통해 비밀번호를 재설정합니다.

#### GraphQL Signature

```graphql theme={null}
mutation ChangePasswordByEmailAuth($input: ChangePasswordByEmailAuthInput!) {
  changePasswordByEmailAuth(input: $input)
}
```

#### 파라미터

<ParamField path="input.email" type="String!" required>
  등록된 이메일 주소
</ParamField>

<ParamField path="input.password" type="String!" required>
  새로운 비밀번호
</ParamField>

<ParamField path="input.emailAuthHash" type="String!" required>
  이메일 인증 해시
</ParamField>

***

### sendPasswordResetEmail

비밀번호 재설정 이메일을 발송합니다.

#### GraphQL Signature

```graphql theme={null}
mutation SendPasswordResetEmail($email: String!) {
  sendPasswordResetEmail(email: $email)
}
```

#### 파라미터

<ParamField path="email" type="String!" required>
  비밀번호를 재설정할 이메일 주소
</ParamField>

#### 응답

<ResponseField name="result" type="Boolean">
  이메일 발송 성공 여부
</ResponseField>

***

### uploadThumbnail

사용자 프로필 이미지를 업로드합니다.

#### GraphQL Signature

```graphql theme={null}
mutation UploadThumbnail($image: Upload!) {
  uploadThumbnail(image: $image)
}
```

#### 파라미터

<ParamField path="image" type="Upload!" required>
  업로드할 이미지 파일
</ParamField>

#### 응답

<ResponseField name="url" type="String">
  업로드된 이미지 URL
</ResponseField>

***

### agreeTerms

약관에 동의합니다.

#### GraphQL Signature

```graphql theme={null}
mutation AgreeTerms($type: String!, $isAgreed: Boolean!) {
  agreeTerms(type: $type, isAgreed: $isAgreed)
}
```

#### 파라미터

<ParamField path="type" type="String!" required>
  약관 타입 (예: "privacy", "terms", "marketing")
</ParamField>

<ParamField path="isAgreed" type="Boolean!" required>
  동의 여부
</ParamField>

#### 응답

<ResponseField name="result" type="Boolean!">
  동의 처리 성공 여부
</ResponseField>

***

## 사용 흐름

### 회원가입 흐름

1. **중복 확인**: `verifyDuplicate`로 아이디, 이메일, 닉네임 중복 확인
2. **SMS 인증** (선택): `requestSMSAuth` → `confirmSMSAuth`로 휴대폰 인증
3. **회원가입**: `signUp`으로 계정 생성
4. **이메일 인증** (선택): `requestEmailVerification` → `verifyEmail`

### 비밀번호 재설정 흐름

**방법 1: SMS 인증**

1. `requestSMSAuth`로 SMS 발송
2. `confirmSMSAuth`로 인증 해시 발급
3. `changePasswordBySMSAuth`로 비밀번호 변경

**방법 2: 이메일 인증**

1. `sendPasswordResetEmail`로 이메일 발송
2. 이메일에서 인증 링크 클릭
3. `changePasswordByEmailAuth`로 비밀번호 변경

## 관련 API

* [인증 API](/api-reference/user-svc/auth) - SMS 및 이메일 인증
* [게시글 API](/api-reference/user-svc/article) - 사용자 알림 관리
