diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 6d5bd3a7..31fb310e 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -58,3 +58,38 @@ jobs: script_stop: true script: | sh deploy/deploy.sh + + deploy-docs: + needs: build + runs-on: ubuntu-latest + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'temurin' + + - name: Grant execute permission to gradlew + run: chmod +x ./gradlew + + - name: Generate AsciiDoc HTML + run: ./gradlew asciidoctor + + - name: Upload GitHub Pages artifact + uses: actions/upload-pages-artifact@v1 + with: + path: build/docs/asciidoc + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/build.gradle b/build.gradle index 40e5042c..d7607c71 100644 --- a/build.gradle +++ b/build.gradle @@ -42,6 +42,7 @@ dependencies { // Spring Security implementation 'org.springframework.boot:spring-boot-starter-security' + testImplementation 'org.springframework.security:spring-security-test' // jwt implementation 'io.jsonwebtoken:jjwt-api:0.11.5' @@ -161,6 +162,7 @@ tasks.jacocoTestCoverageVerification { asciidoctor { + attributes 'projectdir': projectDir inputs.dir snippetsDir configurations 'asciidoctorExt' dependsOn test diff --git a/src/docs/asciidoc/maskpass.adoc b/src/docs/asciidoc/maskpass.adoc new file mode 100644 index 00000000..14d52a3e --- /dev/null +++ b/src/docs/asciidoc/maskpass.adoc @@ -0,0 +1,860 @@ += 마패(MASKPASS) API 명세서 🔐 +:doctype: book +:toc: left +:toclevels: 2 +:sectnums: +:snippets: {projectdir}/build/generated-snippets + +== 소개 + +이 문서는 마패(MASKPASS) 프로젝트의 API 명세서입니다. +주요 기능은 다음과 같습니다: + +- QR 코드 생성 및 조회 +- 실시간 알림(SSE) 구독 +- 사용자 인증 및 회원 관리 +- 예약 등록 및 조회 +- 얼굴 인식 기반 인증 +- 관리자 전용 컨퍼런스/세션 관리 +- 출입 인증 및 출입 내역 조회 + +각 API는 실제 테스트 기반의 요청/응답 예시를 포함하고 있습니다. + +== QR 코드 생성 API + +QR 코드를 생성하여 URL과 함께 반환합니다. +컨퍼런스 ID와 세션 ID를 기반으로 QR을 생성하며, 세션 ID는 선택값입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/admin/qr` +- **Query Parameters:** +- `conferenceId` (필수): 컨퍼런스 ID +- `sessionId` (선택): 세션 ID +- `url` (필수): QR에 포함될 URL + +==== 요청 예시 +include::{snippets}/qr-code-controller-test/qr-code_-create_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** QR 코드 정보 반환 + +==== 응답 예시 +include::{snippets}/qr-code-controller-test/qr-code_-create_-success/http-response.adoc[] + +''' + +QR 코드 생성 과정에서 발생할 수 있는 오류 케이스를 설명합니다. + +''' + +=== 실패 - 존재하지 않는 Conference ID + +요청한 `conferenceId`가 존재하지 않을 때 발생합니다. + +==== 요청 예시 +include::{snippets}/qr-code-controller-test/qr-code_-conference-id_-not-found/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/qr-code-controller-test/qr-code_-conference-id_-not-found/http-response.adoc[] + +''' + +=== 실패 - 존재하지 않는 Session ID + +요청한 `sessionId`가 존재하지 않을 때 발생합니다. + +==== 요청 예시 +include::{snippets}/qr-code-controller-test/qr-code_-session-id_-not-found/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/qr-code-controller-test/qr-code_-session-id_-not-found/http-response.adoc[] + +''' +== SSE 구독 API + +SSE 방식으로 클라이언트가 컨퍼런스에 구독을 요청하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/subscribe` +- **Query Parameters:** +- `conferenceId` (필수): 구독하려는 컨퍼런스 ID + +==== 요청 예시 +include::{snippets}/sse-controller-test/subscribe_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** SSE 스트림 시작 + +==== 응답 예시 +include::{snippets}/sse-controller-test/subscribe_-success/http-response.adoc[] + +''' + +=== 실패 - conferenceId 누락 + +conferenceId 없이 요청했을 때 발생합니다. + +==== 요청 예시 +include::{snippets}/sse-controller-test/subscribe_-none-conference-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/sse-controller-test/subscribe_-none-conference-fails/http-response.adoc[] + +''' + +=== 실패 - emitter 저장 실패 + +서버에 emitter 저장 실패 시 발생합니다. + +==== 요청 예시 +include::{snippets}/sse-controller-test/subscribe_-emitter-not-stored_-should-return-null/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/sse-controller-test/subscribe_-emitter-not-stored_-should-return-null/http-response.adoc[] + +''' + +== 사용자 회원가입 API + +사용자가 이름, 비밀번호, 전화번호를 입력하여 회원가입을 진행하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/users/signup` +- **Content-Type:** `application/json` +- **Request Body 필드:** + - `name` (필수): 사용자 이름 + - `password` (필수): 비밀번호 + - `phone` (필수): 전화번호 + +==== 요청 예시 +include::{snippets}/user-controller-test/sign-up_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `201 Created` +- **응답 내용:** 사용자 정보 반환 + +==== 응답 예시 +include::{snippets}/user-controller-test/sign-up_-success/http-response.adoc[] + +''' + +== 오류 케이스 (회원가입) + +입력값 누락 또는 유효성 검사 실패 시 발생하는 오류입니다. + +=== 실패 - 이름 누락 +include::{snippets}/user-controller-test/sign-up_-name-blank-fails/http-response.adoc[] + +=== 실패 - 비밀번호 누락 +include::{snippets}/user-controller-test/sign-up_-password-blank-fails/http-response.adoc[] + +=== 실패 - 전화번호 누락 +include::{snippets}/user-controller-test/sign-up_-phone-blank-fails/http-response.adoc[] + +=== 실패 - 이메일 누락 +include::{snippets}/user-controller-test/sign-up_-email-blank-fails/http-response.adoc[] + +''' + +== 사용자 조회 API (토큰 기반) + +로그인된 사용자가 자신의 정보를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/users` + +==== 요청 예시 +include::{snippets}/user-controller-test/find-by-token_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 사용자 정보 반환 + +==== 응답 예시 +include::{snippets}/user-controller-test/find-by-token_-success/http-response.adoc[] + +''' + +== 사용자 ID 조회 API + +사용자 ID를 통해 특정 사용자의 정보를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/users/{userId}` + +==== 요청 예시 +include::{snippets}/user-controller-test/get-user-by-id_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 사용자 정보 반환 + +==== 응답 예시 +include::{snippets}/user-controller-test/get-user-by-id_-success/http-response.adoc[] + +''' + +== 전화번호 변경 API + +사용자의 전화번호를 변경하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `PATCH` +- **URL:** `/api/v1/users/phone` +- **Content-Type:** `application/json` + +==== 요청 예시 +include::{snippets}/user-controller-test/set-phone_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 전화번호 변경 완료 응답 + +==== 응답 예시 +include::{snippets}/user-controller-test/set-phone_-success/http-response.adoc[] + +''' + +== 예약 생성 API + +사용자가 특정 컨퍼런스에 대한 예약을 생성하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/reservations` +- **Content-Type:** `application/json` +- **Request Body 필드:** + - `conferenceId` (필수): 예약하려는 컨퍼런스 ID + - `sessionId` (선택): 세션 ID + - `memo` (선택): 메모 + +==== 요청 예시 +include::{snippets}/reservation-controller-test/create-reservation_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `201 Created` +- **응답 내용:** 예약 ID 또는 예약 완료 정보 + +==== 응답 예시 +include::{snippets}/reservation-controller-test/create-reservation_-success/http-response.adoc[] + +''' + +== 예약한 컨퍼런스 목록 조회 API + +사용자가 예약한 컨퍼런스 목록을 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/reservations/conferences` + +==== 요청 예시 +include::{snippets}/reservation-controller-test/내가_예약한_컨퍼런스목록조회_api_테스트/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 예약된 컨퍼런스 목록 + +==== 응답 예시 +include::{snippets}/reservation-controller-test/내가_예약한_컨퍼런스목록조회_api_테스트/http-response.adoc[] + +''' + +== 예약한 특정 컨퍼런스 상세조회 API + +사용자가 예약한 컨퍼런스 중 하나에 대한 상세 정보를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/reservations/conferences/{conferenceId}` + +==== 요청 예시 +include::{snippets}/reservation-controller-test/예약한_특정_컨퍼런스상세조회_api_테스트/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 컨퍼런스 상세 정보 + +==== 응답 예시 +include::{snippets}/reservation-controller-test/예약한_특정_컨퍼런스상세조회_api_테스트/http-response.adoc[] + +''' + +== 예약 임시생성 API + +임시 예약을 생성하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/reservations/temporary` +- **Content-Type:** `application/json` + +==== 요청 예시 +include::{snippets}/reservation-controller-test/예약_임시생성_api테스트/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `201 Created` +- **응답 내용:** 임시 예약 정보 + +==== 응답 예시 +include::{snippets}/reservation-controller-test/예약_임시생성_api테스트/http-response.adoc[] + +''' + +== 사용자와 연결된 예약 전체조회 API + +사용자와 연결된 모든 예약 정보를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/reservations/me` + +==== 요청 예시 +include::{snippets}/reservation-controller-test/내_예약_모두조회_api_테스트/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 예약 목록 반환 + +==== 응답 예시 +include::{snippets}/reservation-controller-test/내_예약_모두조회_api_테스트/http-response.adoc[] + +''' + +== 얼굴 이미지 업로드 API + +사용자의 얼굴 이미지를 업로드하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/face/upload` +- **Content-Type:** `multipart/form-data` +- **요구사항:** 인증 쿠키 필요 + +==== 요청 예시 +include::{snippets}/face-recognition-controller-test/upload-user-face_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 업로드 성공 여부 + +==== 응답 예시 +include::{snippets}/face-recognition-controller-test/upload-user-face_-success/http-response.adoc[] + +''' + +== 얼굴 이미지 삭제 API + +사용자의 얼굴 이미지를 삭제하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `DELETE` +- **URL:** `/api/v1/face/delete` +- **요구사항:** 인증 쿠키 필요 + +==== 요청 예시 +include::{snippets}/face-recognition-controller-test/delete-face-image_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 삭제 성공 여부 + +==== 응답 예시 +include::{snippets}/face-recognition-controller-test/delete-face-image_-success/http-response.adoc[] + +''' + +== 얼굴 기반 인증 API + +사용자의 얼굴 이미지와 등록된 이미지를 비교하여 인증하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/face/authenticate` +- **Content-Type:** `multipart/form-data` + +==== 요청 예시 +include::{snippets}/face-recognition-controller-test/authentication-by-user-face_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 인증 성공 여부 및 사용자 정보 + +==== 응답 예시 +include::{snippets}/face-recognition-controller-test/authentication-by-user-face_-success/http-response.adoc[] + +''' + +== Rekognition Collection 생성 API (관리자용) + +AWS Rekognition Collection을 생성하는 관리자용 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/admin/rekognition/collection` + +==== 요청 예시 +include::{snippets}/face-recognition-controller-test/create-collection_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 생성 완료 메시지 + +==== 응답 예시 +include::{snippets}/face-recognition-controller-test/create-collection_-success/http-response.adoc[] + +''' + +== 얼굴 인식 API 오류 케이스 + +얼굴 이미지 인증, 업로드, 삭제 중 발생할 수 있는 오류 케이스입니다. + +=== 실패 - 얼굴 인증 실패 + +등록된 얼굴과 일치하지 않아 인증이 실패한 경우입니다. + +==== 요청 예시 +include::{snippets}/face-recognition-controller-test/authentication-by-user-face_-when-face-auth_-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/face-recognition-controller-test/authentication-by-user-face_-when-face-auth_-fails/http-response.adoc[] + +''' + +=== 실패 - 쿠키 없음 (업로드 시) + +쿠키가 없어서 사용자를 식별할 수 없는 경우입니다. 얼굴 업로드 시 주로 발생합니다. + +==== 요청 예시 +include::{snippets}/face-recognition-controller-test/upload-user-face_-when-cookie-none_-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/face-recognition-controller-test/upload-user-face_-when-cookie-none_-fails/http-response.adoc[] + +''' + +=== 실패 - 쿠키 없음 (삭제 시) + +쿠키가 없어서 사용자를 식별할 수 없는 경우입니다. 얼굴 삭제 시 주로 발생합니다. + +==== 요청 예시 +include::{snippets}/face-recognition-controller-test/delete-face-image_-when-cookie-none_-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/face-recognition-controller-test/delete-face-image_-when-cookie-none_-fails/http-response.adoc[] + +''' + +== 전체 컨퍼런스 목록 조회 API + +등록된 전체 컨퍼런스를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/conferences` + +==== 요청 예시 +include::{snippets}/conference-controller-test/get-all-conferences_-returns-conference-list/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 컨퍼런스 목록 반환 + +==== 응답 예시 +include::{snippets}/conference-controller-test/get-all-conferences_-returns-conference-list/http-response.adoc[] + +''' + +== 특정 컨퍼런스 조회 API + +특정 ID를 가진 컨퍼런스의 상세 정보를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/conferences/{conferenceId}` + +==== 요청 예시 +include::{snippets}/conference-controller-test/get-conference_-returns-specific-conference/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 해당 컨퍼런스의 상세 정보 + +==== 응답 예시 +include::{snippets}/conference-controller-test/get-conference_-returns-specific-conference/http-response.adoc[] + +''' + +=== 실패 - 존재하지 않는 컨퍼런스 ID + +조회하려는 컨퍼런스가 존재하지 않을 때 발생하는 오류입니다. + +==== 요청 예시 +include::{snippets}/conference-controller-test/get-conference_-not-found/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/conference-controller-test/get-conference_-not-found/http-response.adoc[] + +''' + +== 특정 컨퍼런스의 세션 목록 조회 API + +특정 컨퍼런스에 포함된 세션 목록을 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/conferences/{conferenceId}/sessions` + +==== 요청 예시 +include::{snippets}/conference-controller-test/get-session-detail_-returns-specific-session/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 세션 목록 반환 + +==== 응답 예시 +include::{snippets}/conference-controller-test/get-session-detail_-returns-specific-session/http-response.adoc[] + +''' + +== 세션 상세 조회 API + +특정 세션의 상세 정보를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/sessions/{sessionId}` + +==== 요청 예시 +include::{snippets}/conference-controller-test/get-session-detail_-returns-specific-session/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 세션 상세 정보 + +==== 응답 예시 +include::{snippets}/conference-controller-test/get-session-detail_-returns-specific-session/http-response.adoc[] + +''' + +== [관리자] 전체 컨퍼런스 목록 조회 API + +관리자가 전체 컨퍼런스를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/admin/conferences` + +==== 요청 예시 +include::{snippets}/conference-admin-controller-test/all-conferences_get_success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 전체 컨퍼런스 목록 + +==== 응답 예시 +include::{snippets}/conference-admin-controller-test/all-conferences_get_success/http-response.adoc[] + +''' + +== [관리자] 특정 컨퍼런스 조회 API + +관리자가 특정 컨퍼런스의 정보를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/admin/conferences/{conferenceId}` + +==== 요청 예시 +include::{snippets}/conference-admin-controller-test/conference_get_success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 해당 컨퍼런스의 상세 정보 + +==== 응답 예시 +include::{snippets}/conference-admin-controller-test/conference_get_success/http-response.adoc[] + +''' + +== [관리자] 세션 상태 수정 API + +관리자가 세션의 상태(활성/비활성)를 변경하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `PUT` +- **URL:** `/api/v1/admin/sessions/{sessionId}/status` + +==== 요청 예시 +include::{snippets}/conference-admin-controller-test/session-status_put_success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 상태 변경 결과 + +==== 응답 예시 +include::{snippets}/conference-admin-controller-test/session-status_put_success/http-response.adoc[] + +''' + +== [관리자] 세션 상세 조회 API + +관리자가 세션의 상세 정보를 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/admin/sessions/{sessionId}` + +==== 요청 예시 +include::{snippets}/conference-admin-controller-test/session-detail_get_success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 세션 상세 정보 + +==== 응답 예시 +include::{snippets}/conference-admin-controller-test/session-detail_get_success/http-response.adoc[] + +''' + +== [관리자] 세션 데이터 수정 API + +관리자가 세션의 데이터를 수정하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `PUT` +- **URL:** `/api/v1/admin/sessions/{sessionId}` + +==== 요청 예시 +include::{snippets}/conference-admin-controller-test/session-data_put_success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 수정된 세션 정보 + +==== 응답 예시 +include::{snippets}/conference-admin-controller-test/session-data_put_success/http-response.adoc[] + +''' + +== 로그인 API + +사용자가 이메일과 비밀번호를 통해 로그인하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/auth/login` +- **Content-Type:** `application/json` +- **Request Body 필드:** + - `email` (필수): 사용자 이메일 + - `password` (필수): 사용자 비밀번호 + +==== 요청 예시 +include::{snippets}/auth-controller-test/login_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 로그인 성공 시 사용자 정보 및 인증 토큰 반환 + +==== 응답 예시 +include::{snippets}/auth-controller-test/login_-success/http-response.adoc[] + +''' + +== 로그인 실패 케이스 + +로그인 시 발생 가능한 실패 응답을 설명합니다. + +=== 실패 - 이메일 없음 + +입력된 이메일이 존재하지 않을 경우입니다. + +==== 요청 예시 +include::{snippets}/auth-controller-test/login_-non-existent-email-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/auth-controller-test/login_-non-existent-email-fails/http-response.adoc[] + +''' + +=== 실패 - 이메일 누락 + +이메일을 입력하지 않은 경우입니다. + +==== 요청 예시 +include::{snippets}/auth-controller-test/login_-email-blank-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/auth-controller-test/login_-email-blank-fails/http-response.adoc[] + +''' + +=== 실패 - 비밀번호 누락 + +비밀번호를 입력하지 않은 경우입니다. + +==== 요청 예시 +include::{snippets}/auth-controller-test/login_-password-blank-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/auth-controller-test/login_-password-blank-fails/http-response.adoc[] + +''' + +=== 실패 - 비밀번호 불일치 + +비밀번호가 일치하지 않은 경우입니다. + +==== 요청 예시 +include::{snippets}/auth-controller-test/login-test_-wrong-password-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/auth-controller-test/login-test_-wrong-password-fails/http-response.adoc[] + + +== 출입 인증 API (컨퍼런스 단위) + +QR 토큰을 통해 사용자의 컨퍼런스 출입을 인증하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/attend/token/conference` +- **Content-Type:** `application/json` + +==== 요청 예시 +include::{snippets}/attend-controller-test/find-by-token_-conference-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 입장 인증 성공 메시지 + +==== 응답 예시 +include::{snippets}/attend-controller-test/find-by-token_-conference-success/http-response.adoc[] + +''' + +=== 실패 - 잘못된 컨퍼런스 토큰 + +존재하지 않거나 만료된 토큰으로 컨퍼런스 입장 시도 시 발생합니다. + +==== 요청 예시 +include::{snippets}/attend-controller-test/find-by-token_-conference-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/attend-controller-test/find-by-token_-conference-fails/http-response.adoc[] + +''' + +== 출입 인증 API (세션 단위) + +QR 토큰을 통해 사용자의 세션 출입을 인증하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `POST` +- **URL:** `/api/v1/attend/token/session` +- **Content-Type:** `application/json` + +==== 요청 예시 +include::{snippets}/attend-controller-test/find-by-token_-conference-session-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 세션 입장 인증 성공 메시지 + +==== 응답 예시 +include::{snippets}/attend-controller-test/find-by-token_-conference-session-success/http-response.adoc[] + +''' + +== 출입 요약 정보 조회 API + +사용자의 컨퍼런스 또는 세션 출입 정보를 요약해서 조회하는 API입니다. + +=== 요청 정보 + +- **HTTP Method:** `GET` +- **URL:** `/api/v1/attend/summary` + +==== 요청 예시 +include::{snippets}/attend-controller-test/get-attendance-summary_-success/http-request.adoc[] + +=== 응답 정보 + +- **Status:** `200 OK` +- **응답 내용:** 출입 현황 요약 + +==== 응답 예시 +include::{snippets}/attend-controller-test/get-attendance-summary_-success/http-response.adoc[] + +''' + +=== 실패 - 출입 내역 없음 + +출입한 이력이 존재하지 않는 경우입니다. + +==== 요청 예시 +include::{snippets}/attend-controller-test/get-attendance-summary_-no-attendance_-fails/http-request.adoc[] + +==== 응답 예시 +include::{snippets}/attend-controller-test/get-attendance-summary_-no-attendance_-fails/http-response.adoc[] diff --git a/src/docs/asciidoc/qr-code.adoc b/src/docs/asciidoc/qr-code.adoc deleted file mode 100644 index 7ff6794b..00000000 --- a/src/docs/asciidoc/qr-code.adoc +++ /dev/null @@ -1,65 +0,0 @@ -= QR 코드 API 명세서 -:doctype: book -:toc: left -:toclevels: 2 -:sectnums: -:snippets: {projectdir}/build/generated-snippets - -QR 코드를 생성하고 조회하는 API에 대한 명세서입니다. - -''' - -== QR 코드 생성 API - -QR 코드를 생성하여 URL과 함께 반환합니다. -컨퍼런스 ID와 세션 ID를 기반으로 QR을 생성하며, 세션 ID는 선택값입니다. - -=== 요청 정보 - -- **HTTP Method:** `GET` -- **URL:** `/api/v1/admin/qr` -- **Query Parameters:** -- `conferenceId` (필수): 컨퍼런스 ID -- `sessionId` (선택): 세션 ID -- `url` (필수): QR에 포함될 URL - -==== 요청 예시 -include::{snippets}/qr-code-controller-test/qr-code_-create_-success/http-request.adoc[] - -=== 응답 정보 - -- **Status:** `200 OK` -- **응답 내용:** QR 코드 정보 반환 - -==== 응답 예시 -include::{snippets}/qr-code-controller-test/qr-code_-create_-success/http-response.adoc[] - -''' - -== 오류 케이스 - -QR 코드 생성 과정에서 발생할 수 있는 오류 케이스를 설명합니다. - -''' - -=== 실패 - 존재하지 않는 Conference ID - -요청한 `conferenceId`가 존재하지 않을 때 발생합니다. - -==== 요청 예시 -include::{snippets}/qr-code-controller-test/qr-code_-conference-id_-not-found/http-request.adoc[] - -==== 응답 예시 -include::{snippets}/qr-code-controller-test/qr-code_-conference-id_-not-found/http-response.adoc[] - -''' - -=== 실패 - 존재하지 않는 Session ID - -요청한 `sessionId`가 존재하지 않을 때 발생합니다. - -==== 요청 예시 -include::{snippets}/qr-code-controller-test/qr-code_-session-id_-not-found/http-request.adoc[] - -==== 응답 예시 -include::{snippets}/qr-code-controller-test/qr-code_-session-id_-not-found/http-response.adoc[] \ No newline at end of file diff --git a/src/main/resources/static/docs/maskpass.html b/src/main/resources/static/docs/maskpass.html new file mode 100644 index 00000000..7284e74d --- /dev/null +++ b/src/main/resources/static/docs/maskpass.html @@ -0,0 +1,3455 @@ + + + + + + + +마패(MASKPASS) API 명세서 🔐 + + + + + +
+
+

1. 소개

+
+
+

이 문서는 마패(MASKPASS) 프로젝트의 API 명세서입니다. +주요 기능은 다음과 같습니다:

+
+
+
    +
  • +

    QR 코드 생성 및 조회

    +
  • +
  • +

    실시간 알림(SSE) 구독

    +
  • +
  • +

    사용자 인증 및 회원 관리

    +
  • +
  • +

    예약 등록 및 조회

    +
  • +
  • +

    얼굴 인식 기반 인증

    +
  • +
  • +

    관리자 전용 컨퍼런스/세션 관리

    +
  • +
  • +

    출입 인증 및 출입 내역 조회

    +
  • +
+
+
+

각 API는 실제 테스트 기반의 요청/응답 예시를 포함하고 있습니다.

+
+
+
+
+

2. QR 코드 생성 API

+
+
+

QR 코드를 생성하여 URL과 함께 반환합니다. +컨퍼런스 ID와 세션 ID를 기반으로 QR을 생성하며, 세션 ID는 선택값입니다.

+
+
+

2.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/admin/qr

    +
  • +
  • +

    Query Parameters:

    +
  • +
  • +

    conferenceId (필수): 컨퍼런스 ID

    +
  • +
  • +

    sessionId (선택): 세션 ID

    +
  • +
  • +

    url (필수): QR에 포함될 URL

    +
  • +
+
+
+

2.1.1. 요청 예시

+
+
+
GET /api/v1/admin/qr?conferenceId=1&sessionId=1&url=https%3A%2F%2Fwww.google.com HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTgwLCJleHAiOjE3NDM0MTM5ODB9.Rp1RDIQpTV_zyZnNcLQinkxtz1h6zUmtBlBT06j7xKk
+
+
+
+
+
+

2.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: QR 코드 정보 반환

    +
  • +
+
+
+

2.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : {
+    "qrImageBase64" : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABRBrPYAAABWUlEQVR4Xu3SQXLFIAwDUG7G1TlSb0At2c5PGQxddjrybwJIj02mbf5mvtqabEdsGbFlxJYRW+bvs9E4fY6OE1a8MhWrGLboGv7Qh8xOrGBoRgK8yCIVu7DRuJlY++ey2IVxh3jmNbEzC4yQHVGkYiVrHFavX6RiFXsPP7A/nxHbMn7I7m8cfnxlsZJZZQgCy/ALfmnSiW1ZxKSTqnudI7Zn3UP2MzDWLMRKxh8LU17GDbGKAbrGP+eM/1LciUZsz7zoyNIitC02YhVD2PHw3dD7w1isYFEy5RreDlRiJ9bxDFL0Ly9WMjZuAZ4ASOzArGI2uOAdWuzAWEE2DI7cORUrWI6HuPRcFDswHi0YltnjAtSRWMV4iNbWQZ25WM3wIVHzQ0NO31GL3RgbqoxxFLsy9tDPMBErWGKzULjSEWARK1l8yVhTcYtebM+uI7aM2DJiy4gt8x/YNwZLcY/cLtB6AAAAAElFTkSuQmCC"
+  },
+  "status" : true
+}
+
+
+
+
+

QR 코드 생성 과정에서 발생할 수 있는 오류 케이스를 설명합니다.

+
+
+
+
+
+

2.3. 실패 - 존재하지 않는 Conference ID

+
+

요청한 `conferenceId`가 존재하지 않을 때 발생합니다.

+
+
+

2.3.1. 요청 예시

+
+
+
GET /api/v1/admin/qr?conferenceId=999&sessionId=2&url=https%3A%2F%2Fwww.google.com HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjIsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTgwLCJleHAiOjE3NDM0MTM5ODB9.nARnu90ZLrmZ3R4IP77t2PR7_a2jB6Lsrp8s-lXD4pU
+
+
+
+
+

2.3.2. 응답 예시

+
+
+
HTTP/1.1 404 Not Found
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "존재하지 않는 컨퍼런스입니다."
+}
+
+
+
+
+
+
+

2.4. 실패 - 존재하지 않는 Session ID

+
+

요청한 `sessionId`가 존재하지 않을 때 발생합니다.

+
+
+

2.4.1. 요청 예시

+
+
+
GET /api/v1/admin/qr?conferenceId=3&sessionId=999&url=https%3A%2F%2Fwww.google.com HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjMsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTgwLCJleHAiOjE3NDM0MTM5ODB9.l4cP4LvdymwjfMxvFlJ4rmhlXotKuXfyNWfi35d_66w
+
+
+
+
+

2.4.2. 응답 예시

+
+
+
HTTP/1.1 404 Not Found
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "존재하지 않는 세션입니다."
+}
+
+
+
+
+
+
+
+
+

3. SSE 구독 API

+
+
+

SSE 방식으로 클라이언트가 컨퍼런스에 구독을 요청하는 API입니다.

+
+
+

3.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/subscribe

    +
  • +
  • +

    Query Parameters:

    +
  • +
  • +

    conferenceId (필수): 구독하려는 컨퍼런스 ID

    +
  • +
+
+
+

3.1.1. 요청 예시

+
+
+
GET /api/v1/sse/subscribe?conferenceId=1&sessionId=2 HTTP/1.1
+Accept: text/event-stream
+
+
+
+
+
+

3.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: SSE 스트림 시작

    +
  • +
+
+
+

3.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: text/event-stream
+
+id:conference:1:session:2
+event:AttendanceCount
+data:0
+retry:1000
+
+
+
+
+
+
+

3.3. 실패 - conferenceId 누락

+
+

conferenceId 없이 요청했을 때 발생합니다.

+
+
+

3.3.1. 요청 예시

+
+
+
GET /api/v1/sse/subscribe?sessionId=2 HTTP/1.1
+Accept: text/event-stream
+
+
+
+
+

3.3.2. 응답 예시

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+
+
+
+
+
+
+

3.4. 실패 - emitter 저장 실패

+
+

서버에 emitter 저장 실패 시 발생합니다.

+
+
+

3.4.1. 요청 예시

+
+
+
GET /api/v1/sse/subscribe?conferenceId=1&sessionId=2 HTTP/1.1
+Accept: text/event-stream
+
+
+
+
+

3.4.2. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: text/event-stream
+
+id:conference:1:session:2
+event:AttendanceCount
+data:0
+retry:1000
+
+
+
+
+
+
+
+
+

4. 사용자 회원가입 API

+
+
+

사용자가 이름, 비밀번호, 전화번호를 입력하여 회원가입을 진행하는 API입니다.

+
+
+

4.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/users/signup

    +
  • +
  • +

    Content-Type: application/json

    +
  • +
  • +

    Request Body 필드:

    +
  • +
  • +

    name (필수): 사용자 이름

    +
  • +
  • +

    password (필수): 비밀번호

    +
  • +
  • +

    phone (필수): 전화번호

    +
  • +
+
+
+

4.1.1. 요청 예시

+
+
+
POST /api/v1/users/signup HTTP/1.1
+Content-Type: application/json
+
+{
+  "name" : "홍길동",
+  "email" : "test@naver.com",
+  "password" : "4321",
+  "phone" : "010-1234-5678"
+}
+
+
+
+
+
+

4.2. 응답 정보

+
+
    +
  • +

    Status: 201 Created

    +
  • +
  • +

    응답 내용: 사용자 정보 반환

    +
  • +
+
+
+

4.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 13,
+    "email" : "test@naver.com",
+    "phone" : "010-1234-5678",
+    "name" : "홍길동",
+    "role" : "USER",
+    "hasFace" : false,
+    "createdAt" : "2025-03-31T18:09:41.532826"
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

5. 오류 케이스 (회원가입)

+
+
+

입력값 누락 또는 유효성 검사 실패 시 발생하는 오류입니다.

+
+
+

5.1. 실패 - 이름 누락

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "잘못된 요청입니다.",
+  "validationErrors" : [ {
+    "field" : "name",
+    "message" : "이름을 입력해 주세요."
+  } ]
+}
+
+
+
+
+

5.2. 실패 - 비밀번호 누락

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "잘못된 요청입니다.",
+  "validationErrors" : [ {
+    "field" : "password",
+    "message" : "비밀번호를 입력해 주세요."
+  } ]
+}
+
+
+
+
+

5.3. 실패 - 전화번호 누락

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "잘못된 요청입니다.",
+  "validationErrors" : [ {
+    "field" : "phone",
+    "message" : "전화 번호를 입력해 주세요."
+  } ]
+}
+
+
+
+
+

5.4. 실패 - 이메일 누락

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "잘못된 요청입니다.",
+  "validationErrors" : [ {
+    "field" : "email",
+    "message" : "이메일을 입력해 주세요."
+  } ]
+}
+
+
+
+
+
+
+
+

6. 사용자 조회 API (토큰 기반)

+
+
+

로그인된 사용자가 자신의 정보를 조회하는 API입니다.

+
+
+

6.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/users

    +
  • +
+
+
+

6.1.1. 요청 예시

+
+
+
GET /api/v1/users HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEwLCJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MzQxMjE4MSwiZXhwIjoxNzQzNDEzOTgxfQ.US_atwFESIXuJSVp2JchazP3ut5_2-J49KB_lwxkN1A
+
+
+
+
+
+

6.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 사용자 정보 반환

    +
  • +
+
+
+

6.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 10,
+    "email" : "test@gmail.com",
+    "name" : "홍길순",
+    "phone" : "01011112222",
+    "isDeleted" : false,
+    "role" : "USER",
+    "hasFace" : false
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

7. 사용자 ID 조회 API

+
+
+

사용자 ID를 통해 특정 사용자의 정보를 조회하는 API입니다.

+
+
+

7.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/users/{userId}

    +
  • +
+
+
+

7.1.1. 요청 예시

+
+
+
GET /api/v1/users/14 HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjE0LCJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MzQxMjE4MSwiZXhwIjoxNzQzNDEzOTgxfQ.turoP9czc4Vi0OwtbgOfm5vcRoK4-moceNY_NewNPA8
+
+
+
+
+
+

7.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 사용자 정보 반환

    +
  • +
+
+
+

7.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 14,
+    "email" : "test@gmail.com",
+    "name" : "홍길순",
+    "phone" : "01011112222",
+    "isDeleted" : false,
+    "role" : "USER",
+    "hasFace" : false
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

8. 전화번호 변경 API

+
+
+

사용자의 전화번호를 변경하는 API입니다.

+
+
+

8.1. 요청 정보

+
+
    +
  • +

    HTTP Method: PATCH

    +
  • +
  • +

    URL: /api/v1/users/phone

    +
  • +
  • +

    Content-Type: application/json

    +
  • +
+
+
+

8.1.1. 요청 예시

+
+
+
PUT /api/v1/users/phone HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjE4LCJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MzQxMjE4MSwiZXhwIjoxNzQzNDEzOTgxfQ.CK8dUbm_e00nBfWk49OqW_h4iVa_DO70EnnS2ExN9qo
+
+{
+  "phone" : "01012345678"
+}
+
+
+
+
+
+

8.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 전화번호 변경 완료 응답

    +
  • +
+
+
+

8.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: text/plain;charset=UTF-8
+
+소셜 로그인 유저 전화번호 등록 완료
+
+
+
+
+
+
+
+
+

9. 예약 생성 API

+
+
+

사용자가 특정 컨퍼런스에 대한 예약을 생성하는 API입니다.

+
+
+

9.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/reservations

    +
  • +
  • +

    Content-Type: application/json

    +
  • +
  • +

    Request Body 필드:

    +
  • +
  • +

    conferenceId (필수): 예약하려는 컨퍼런스 ID

    +
  • +
  • +

    sessionId (선택): 세션 ID

    +
  • +
  • +

    memo (선택): 메모

    +
  • +
+
+
+

9.1.1. 요청 예시

+
+
+
POST /api/v1/reservation/create HTTP/1.1
+Content-Type: application/json
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjgsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJuYW1lIjoi7ZmN6ri47IicIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MjIyODMyNSwiZXhwIjoxNzQyMjMwMTI1fQ.IkBJulw1Q032jeu_GFZrOaD0B8NYNnfj8zVFvPGAjLE
+
+{
+  "conferenceId" : 8,
+  "sessionIds" : [ 8, 9 ],
+  "name" : "홍길동",
+  "phone" : "01012345678"
+}
+
+
+
+
+
+

9.2. 응답 정보

+
+
    +
  • +

    Status: 201 Created

    +
  • +
  • +

    응답 내용: 예약 ID 또는 예약 완료 정보

    +
  • +
+
+
+

9.2.1. 응답 예시

+
+
+
HTTP/1.1 201 Created
+Content-Type: application/json
+
+{
+  "reservationId" : 1,
+  "conference" : {
+    "conferenceId" : 8,
+    "conferenceName" : "테스트 컨퍼런스",
+    "description" : "테스트 컨퍼런스 소개",
+    "location" : "테스트 주소 1234",
+    "conferenceAt" : "2025-03-18T01:18:45.767377",
+    "capacity" : 100,
+    "hasSessions" : true
+  },
+  "sessions" : [ {
+    "sessionId" : 8,
+    "conferenceId" : 8,
+    "sessionName" : "테스트 세션",
+    "capacity" : 100,
+    "location" : "온라인",
+    "time" : "2025-03-18T01:18:45.768326",
+    "summary" : "테스트 세션 요약"
+  }, {
+    "sessionId" : 9,
+    "conferenceId" : 8,
+    "sessionName" : "테스트 세션",
+    "capacity" : 100,
+    "location" : "온라인",
+    "time" : "2025-03-18T01:18:45.768331",
+    "summary" : "테스트 세션 요약"
+  } ],
+  "status" : "CONFIRMED"
+}
+
+
+
+
+
+
+
+
+

10. 예약한 컨퍼런스 목록 조회 API

+
+
+

사용자가 예약한 컨퍼런스 목록을 조회하는 API입니다.

+
+
+

10.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/reservations/conferences

    +
  • +
+
+
+

10.1.1. 요청 예시

+
+
+
GET /api/v1/reservation/my/conference HTTP/1.1
+Content-Type: application/json
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjYsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTgxLCJleHAiOjE3NDM0MTM5ODF9.Q7FyKfcS3dArNUY7hUmnsLYvlaxpfH0gKyXjDs5ssEM
+
+
+
+
+
+

10.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 예약된 컨퍼런스 목록

    +
  • +
+
+
+

10.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : [ {
+    "id" : 6,
+    "name" : "테스트 컨퍼런스",
+    "description" : null,
+    "location" : "테스트 주소 1234",
+    "startTime" : "2025-03-31T18:09:41.158762",
+    "endTime" : "2025-03-31T18:09:41.158763",
+    "capacity" : null,
+    "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090941Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=b40e5a4701ecf17234490c5eae8f57620eff212d819676b528b928d8a97c4dfa",
+    "isActive" : null,
+    "hasSessions" : null,
+    "sessions" : null
+  } ],
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

11. 예약한 특정 컨퍼런스 상세조회 API

+
+
+

사용자가 예약한 컨퍼런스 중 하나에 대한 상세 정보를 조회하는 API입니다.

+
+
+

11.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/reservations/conferences/{conferenceId}

    +
  • +
+
+
+

11.1.1. 요청 예시

+
+
+
GET /api/v1/reservation/my/conference/7 HTTP/1.1
+Content-Type: application/json
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjcsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTgxLCJleHAiOjE3NDM0MTM5ODF9.nzcEVElGHJ43ByRZxO7pCDhSKO3JboR1r3p9F2ajsHw
+
+
+
+
+
+

11.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 컨퍼런스 상세 정보

    +
  • +
+
+
+

11.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : {
+    "conferenceId" : 7,
+    "conferenceName" : "테스트 컨퍼런스",
+    "conferenceLocation" : "테스트 주소 1234",
+    "startTime" : "2025-03-31T18:09:41.176068",
+    "endTime" : "2025-03-31T18:09:41.176069",
+    "conferenceDescription" : "테스트 컨퍼런스 소개",
+    "sessions" : [ {
+      "id" : 7,
+      "conferenceId" : 7,
+      "name" : "테스트 세션",
+      "capacity" : 100,
+      "location" : "온라인",
+      "startTime" : "2025-03-31T18:09:41.176536",
+      "endTime" : "2025-03-31T18:09:41.176537",
+      "summary" : "테스트 세션 요약",
+      "speakerName" : "발표자",
+      "speakerOrganization" : "발표자 소속",
+      "isActive" : true,
+      "speakerImage" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090941Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=b40e5a4701ecf17234490c5eae8f57620eff212d819676b528b928d8a97c4dfa",
+      "speakerStatus" : true
+    } ]
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

12. 예약 임시생성 API

+
+
+

임시 예약을 생성하는 API입니다.

+
+
+

12.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/reservations/temporary

    +
  • +
  • +

    Content-Type: application/json

    +
  • +
+
+
+

12.1.1. 요청 예시

+
+
+
POST /api/v1/reservation/temp HTTP/1.1
+Content-Type: application/json
+
+{
+  "sessionIds" : [ 5 ],
+  "name" : "홍길순",
+  "phone" : "01011112222",
+  "conferenceId" : 5
+}
+
+
+
+
+
+

12.2. 응답 정보

+
+
    +
  • +

    Status: 201 Created

    +
  • +
  • +

    응답 내용: 임시 예약 정보

    +
  • +
+
+
+

12.2.1. 응답 예시

+
+
+
HTTP/1.1 201 Created
+Content-Type: application/json
+
+{
+  "data" : {
+    "reservationId" : 3,
+    "conference" : {
+      "conferenceId" : 5,
+      "conferenceName" : "테스트 컨퍼런스",
+      "description" : "테스트 컨퍼런스 소개",
+      "location" : "테스트 주소 1234",
+      "startTime" : "2025-03-31T18:09:41.13541",
+      "endTime" : "2025-03-31T18:09:41.135411",
+      "capacity" : 100,
+      "hasSessions" : true,
+      "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090941Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=b40e5a4701ecf17234490c5eae8f57620eff212d819676b528b928d8a97c4dfa"
+    },
+    "sessions" : [ {
+      "sessionId" : 5,
+      "conferenceId" : 5,
+      "sessionName" : "테스트 세션",
+      "capacity" : 100,
+      "location" : "온라인",
+      "startTime" : "2025-03-31T18:09:41.135877",
+      "endTime" : "2025-03-31T18:09:41.135878",
+      "summary" : "테스트 세션 요약",
+      "speaker" : "발표자",
+      "speakerOrganization" : "발표자 소속",
+      "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090941Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=b40e5a4701ecf17234490c5eae8f57620eff212d819676b528b928d8a97c4dfa"
+    } ],
+    "status" : "TEMPORARY"
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

13. 사용자와 연결된 예약 전체조회 API

+
+
+

사용자와 연결된 모든 예약 정보를 조회하는 API입니다.

+
+
+

13.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/reservations/me

    +
  • +
+
+
+

13.1.1. 요청 예시

+
+
+
GET /api/v1/reservation/my HTTP/1.1
+Content-Type: application/json
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjQsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTgxLCJleHAiOjE3NDM0MTM5ODF9.U3K53otDpA2BO7bLNYHrb_aFGlJruVyY58GgD2gJQYI
+
+
+
+
+
+

13.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 예약 목록 반환

    +
  • +
+
+
+

13.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : [ {
+    "reservationId" : 1,
+    "conference" : {
+      "conferenceId" : 4,
+      "conferenceName" : "테스트 컨퍼런스",
+      "description" : "테스트 컨퍼런스 소개",
+      "location" : "테스트 주소 1234",
+      "startTime" : "2025-03-31T18:09:41.105837",
+      "endTime" : "2025-03-31T18:09:41.105839",
+      "capacity" : 100,
+      "hasSessions" : true,
+      "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090941Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=b40e5a4701ecf17234490c5eae8f57620eff212d819676b528b928d8a97c4dfa"
+    },
+    "sessions" : [ {
+      "sessionId" : 4,
+      "conferenceId" : 4,
+      "sessionName" : "테스트 세션",
+      "capacity" : 100,
+      "location" : "온라인",
+      "startTime" : "2025-03-31T18:09:41.106461",
+      "endTime" : "2025-03-31T18:09:41.106462",
+      "summary" : "테스트 세션 요약",
+      "speaker" : "발표자",
+      "speakerOrganization" : "발표자 소속",
+      "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090941Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=b40e5a4701ecf17234490c5eae8f57620eff212d819676b528b928d8a97c4dfa"
+    } ],
+    "status" : "CONFIRMED"
+  } ],
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

14. 얼굴 이미지 업로드 API

+
+
+

사용자의 얼굴 이미지를 업로드하는 API입니다.

+
+
+

14.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/face/upload

    +
  • +
  • +

    Content-Type: multipart/form-data

    +
  • +
  • +

    요구사항: 인증 쿠키 필요

    +
  • +
+
+
+

14.1.1. 요청 예시

+
+
+
POST /api/v1/face/upload HTTP/1.1
+Content-Type: multipart/form-data; boundary=6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
+Cookie: Authorization=testToken
+
+--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
+Content-Disposition: form-data; name=faceImage; filename=face.jpg
+Content-Type: image/jpeg
+
+
+--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm--
+
+
+
+
+
+

14.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 업로드 성공 여부

    +
  • +
+
+
+

14.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 1,
+    "userId" : 1,
+    "rekognitionId" : "rekognition-12345"
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

15. 얼굴 이미지 삭제 API

+
+
+

사용자의 얼굴 이미지를 삭제하는 API입니다.

+
+
+

15.1. 요청 정보

+
+
    +
  • +

    HTTP Method: DELETE

    +
  • +
  • +

    URL: /api/v1/face/delete

    +
  • +
  • +

    요구사항: 인증 쿠키 필요

    +
  • +
+
+
+

15.1.1. 요청 예시

+
+
+
DELETE /api/v1/face/delete HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=testToken
+
+
+
+
+
+

15.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 삭제 성공 여부

    +
  • +
+
+
+

15.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : "얼굴 이미지 삭제 완료",
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

16. 얼굴 기반 인증 API

+
+
+

사용자의 얼굴 이미지와 등록된 이미지를 비교하여 인증하는 API입니다.

+
+
+

16.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/face/authenticate

    +
  • +
  • +

    Content-Type: multipart/form-data

    +
  • +
+
+
+

16.1.1. 요청 예시

+
+
+
POST /api/v1/face/authentication HTTP/1.1
+Content-Type: multipart/form-data; boundary=6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
+
+--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
+Content-Disposition: form-data; name=faceImage; filename=face.jpg
+Content-Type: image/jpeg
+
+
+--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm--
+
+
+
+
+
+

16.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 인증 성공 여부 및 사용자 정보

    +
  • +
+
+
+

16.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "userId" : 1,
+    "similarity" : 99.5
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

17. Rekognition Collection 생성 API (관리자용)

+
+
+

AWS Rekognition Collection을 생성하는 관리자용 API입니다.

+
+
+

17.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/admin/rekognition/collection

    +
  • +
+
+
+

17.1.1. 요청 예시

+
+
+
POST /api/v1/face/collection HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=testToken
+
+
+
+
+
+

17.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 생성 완료 메시지

    +
  • +
+
+
+

17.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : "Rekognition Collection 생성 완료!",
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

18. 얼굴 인식 API 오류 케이스

+
+
+

얼굴 이미지 인증, 업로드, 삭제 중 발생할 수 있는 오류 케이스입니다.

+
+
+

18.1. 실패 - 얼굴 인증 실패

+
+

등록된 얼굴과 일치하지 않아 인증이 실패한 경우입니다.

+
+
+

18.1.1. 요청 예시

+
+
+
POST /api/v1/face/authentication HTTP/1.1
+Content-Type: multipart/form-data; boundary=6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
+
+--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
+Content-Disposition: form-data; name=faceImage; filename=face.jpg
+Content-Type: image/jpeg
+
+
+--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm--
+
+
+
+
+

18.1.2. 응답 예시

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "Rekognition 얼굴 매칭에 실패하였습니다."
+}
+
+
+
+
+
+
+

18.2. 실패 - 쿠키 없음 (업로드 시)

+
+

쿠키가 없어서 사용자를 식별할 수 없는 경우입니다. 얼굴 업로드 시 주로 발생합니다.

+
+
+

18.2.1. 요청 예시

+
+
+
POST /api/v1/face/upload HTTP/1.1
+Content-Type: multipart/form-data; boundary=6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
+
+--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
+Content-Disposition: form-data; name=faceImage; filename=face.jpg
+Content-Type: image/jpeg
+
+
+--6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm--
+
+
+
+
+

18.2.2. 응답 예시

+
+
+
HTTP/1.1 401 Unauthorized
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json;charset=UTF-8
+
+{
+  "status" : false,
+  "message" : "인증에 실패하였습니다. 다시 로그인 해 주세요."
+}
+
+
+
+
+
+
+

18.3. 실패 - 쿠키 없음 (삭제 시)

+
+

쿠키가 없어서 사용자를 식별할 수 없는 경우입니다. 얼굴 삭제 시 주로 발생합니다.

+
+
+

18.3.1. 요청 예시

+
+
+
DELETE /api/v1/face/delete HTTP/1.1
+Content-Type: application/json
+
+
+
+
+

18.3.2. 응답 예시

+
+
+
HTTP/1.1 401 Unauthorized
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json;charset=UTF-8
+
+{
+  "status" : false,
+  "message" : "인증에 실패하였습니다. 다시 로그인 해 주세요."
+}
+
+
+
+
+
+
+
+
+

19. 전체 컨퍼런스 목록 조회 API

+
+
+

등록된 전체 컨퍼런스를 조회하는 API입니다.

+
+
+

19.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/conferences

    +
  • +
+
+
+

19.1.1. 요청 예시

+
+
+
GET /api/v1/conference HTTP/1.1
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEzLCJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MzQxMjE3OCwiZXhwIjoxNzQzNDEzOTc4fQ.2ef19WN6vWBsUIScLj3GRvol6aixMZcR2ljJa96XQI0
+
+
+
+
+
+

19.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 컨퍼런스 목록 반환

    +
  • +
+
+
+

19.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : [ {
+    "id" : 8,
+    "name" : "테스트 컨퍼런스",
+    "description" : "테스트 컨퍼런스 소개",
+    "location" : "테스트 주소 1234",
+    "startTime" : "2025-03-31T18:09:38.145174",
+    "endTime" : "2025-03-31T18:09:38.145175",
+    "capacity" : 100,
+    "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+    "isActive" : true,
+    "hasSessions" : true,
+    "sessions" : [ ]
+  } ],
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

20. 특정 컨퍼런스 조회 API

+
+
+

특정 ID를 가진 컨퍼런스의 상세 정보를 조회하는 API입니다.

+
+
+

20.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/conferences/{conferenceId}

    +
  • +
+
+
+

20.1.1. 요청 예시

+
+
+
GET /api/v1/conference/7 HTTP/1.1
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEyLCJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MzQxMjE3OCwiZXhwIjoxNzQzNDEzOTc4fQ.aeYIVZad4z852dGjnov2iWKzV2DsV3IkQ9s57IDZ5aA
+
+
+
+
+
+

20.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 해당 컨퍼런스의 상세 정보

    +
  • +
+
+
+

20.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 7,
+    "name" : "테스트 컨퍼런스",
+    "description" : "테스트 컨퍼런스 소개",
+    "location" : "테스트 주소 1234",
+    "startTime" : "2025-03-31T18:09:38.129799",
+    "endTime" : "2025-03-31T18:09:38.1298",
+    "capacity" : 100,
+    "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+    "isActive" : true,
+    "hasSessions" : true,
+    "sessions" : [ {
+      "id" : 7,
+      "conferenceId" : 7,
+      "name" : "테스트 세션",
+      "capacity" : 100,
+      "location" : "온라인",
+      "startTime" : "2025-03-31T18:09:38.130369",
+      "endTime" : "2025-03-31T18:09:38.130371",
+      "summary" : "테스트 세션 요약",
+      "speakerName" : "발표자",
+      "speakerOrganization" : "발표자 소속",
+      "isActive" : true,
+      "speakerImage" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+      "speakerStatus" : true
+    } ]
+  },
+  "status" : true
+}
+
+
+
+
+
+
+

20.3. 실패 - 존재하지 않는 컨퍼런스 ID

+
+

조회하려는 컨퍼런스가 존재하지 않을 때 발생하는 오류입니다.

+
+
+

20.3.1. 요청 예시

+
+
+
GET /api/v1/conference/999 HTTP/1.1
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjQsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJuYW1lIjoi7ZmN6ri47IicIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MjM2MTIyOSwiZXhwIjoxNzQyMzYzMDI5fQ.h9x-0PTY2-jaFcqh4mkQdoePT4TrHPSNJef-D5VQljY
+
+
+
+
+

20.3.2. 응답 예시

+
+
+
HTTP/1.1 404 Not Found
+Content-Type: application/json
+
+{
+  "status" : "NOT_FOUND",
+  "message" : "존재하지 않는 컨퍼런스입니다."
+}
+
+
+
+
+
+
+
+
+

21. 특정 컨퍼런스의 세션 목록 조회 API

+
+
+

특정 컨퍼런스에 포함된 세션 목록을 조회하는 API입니다.

+
+
+

21.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/conferences/{conferenceId}/sessions

    +
  • +
+
+
+

21.1.1. 요청 예시

+
+
+
GET /api/v1/conference/6/sessions/6 HTTP/1.1
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjExLCJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MzQxMjE3OCwiZXhwIjoxNzQzNDEzOTc4fQ.pNyxJEL9UCf2GAP7E2uF51dpyDIbcnB2k_V4veMmfMY
+
+
+
+
+
+

21.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 세션 목록 반환

    +
  • +
+
+
+

21.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 6,
+    "conferenceId" : 6,
+    "name" : "테스트 세션",
+    "capacity" : 100,
+    "location" : "온라인",
+    "startTime" : "2025-03-31T18:09:38.11475",
+    "endTime" : "2025-03-31T18:09:38.114752",
+    "summary" : "테스트 세션 요약",
+    "speakerName" : "발표자",
+    "speakerOrganization" : "발표자 소속",
+    "isActive" : true,
+    "speakerImage" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+    "speakerStatus" : true
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

22. 세션 상세 조회 API

+
+
+

특정 세션의 상세 정보를 조회하는 API입니다.

+
+
+

22.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/sessions/{sessionId}

    +
  • +
+
+
+

22.1.1. 요청 예시

+
+
+
GET /api/v1/conference/6/sessions/6 HTTP/1.1
+Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjExLCJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwicm9sZSI6IlJPTEVfVVNFUiIsImlhdCI6MTc0MzQxMjE3OCwiZXhwIjoxNzQzNDEzOTc4fQ.pNyxJEL9UCf2GAP7E2uF51dpyDIbcnB2k_V4veMmfMY
+
+
+
+
+
+

22.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 세션 상세 정보

    +
  • +
+
+
+

22.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 6,
+    "conferenceId" : 6,
+    "name" : "테스트 세션",
+    "capacity" : 100,
+    "location" : "온라인",
+    "startTime" : "2025-03-31T18:09:38.11475",
+    "endTime" : "2025-03-31T18:09:38.114752",
+    "summary" : "테스트 세션 요약",
+    "speakerName" : "발표자",
+    "speakerOrganization" : "발표자 소속",
+    "isActive" : true,
+    "speakerImage" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+    "speakerStatus" : true
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

23. [관리자] 전체 컨퍼런스 목록 조회 API

+
+
+

관리자가 전체 컨퍼런스를 조회하는 API입니다.

+
+
+

23.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/admin/conferences

    +
  • +
+
+
+

23.1.1. 요청 예시

+
+
+
GET /api/v1/admin/conference HTTP/1.1
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjksImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9BRE1JTiIsImlhdCI6MTc0MzQxMjE3OCwiZXhwIjoxNzQzNDEzOTc4fQ.q3TvzMGykSdCQrfNfodbGQZoQ-3HbgV7xitEGN-_ax8
+
+
+
+
+
+

23.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 전체 컨퍼런스 목록

    +
  • +
+
+
+

23.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : [ {
+    "id" : 4,
+    "name" : "테스트 컨퍼런스",
+    "description" : "테스트 컨퍼런스 소개",
+    "location" : "테스트 주소 1234",
+    "startTime" : "2025-03-31T18:09:38.078067",
+    "endTime" : "2025-03-31T18:09:38.078068",
+    "capacity" : 100,
+    "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+    "isActive" : true,
+    "hasSessions" : true,
+    "sessions" : [ ]
+  } ],
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

24. [관리자] 특정 컨퍼런스 조회 API

+
+
+

관리자가 특정 컨퍼런스의 정보를 조회하는 API입니다.

+
+
+

24.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/admin/conferences/{conferenceId}

    +
  • +
+
+
+

24.1.1. 요청 예시

+
+
+
GET /api/v1/admin/conference/2 HTTP/1.1
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjcsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9BRE1JTiIsImlhdCI6MTc0MzQxMjE3OCwiZXhwIjoxNzQzNDEzOTc4fQ.dU7LUm-4IJD0RsQ5rGV7EKP8whJryMbIDfjWBfFxnh4
+
+
+
+
+
+

24.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 해당 컨퍼런스의 상세 정보

    +
  • +
+
+
+

24.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 2,
+    "name" : "테스트 컨퍼런스",
+    "description" : "테스트 컨퍼런스 소개",
+    "location" : "테스트 주소 1234",
+    "startTime" : "2025-03-31T18:09:38.045848",
+    "endTime" : "2025-03-31T18:09:38.045851",
+    "capacity" : 100,
+    "imageUrl" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+    "isActive" : true,
+    "hasSessions" : true,
+    "sessions" : [ {
+      "id" : 2,
+      "conferenceId" : 2,
+      "name" : "테스트 세션",
+      "capacity" : 100,
+      "location" : "온라인",
+      "startTime" : "2025-03-31T18:09:38.046622",
+      "endTime" : "2025-03-31T18:09:38.046625",
+      "summary" : "테스트 세션 요약",
+      "speakerName" : "발표자",
+      "speakerOrganization" : "발표자 소속",
+      "isActive" : true,
+      "speakerImage" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+      "speakerStatus" : true
+    } ]
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

25. [관리자] 세션 상태 수정 API

+
+
+

관리자가 세션의 상태(활성/비활성)를 변경하는 API입니다.

+
+
+

25.1. 요청 정보

+
+
    +
  • +

    HTTP Method: PUT

    +
  • +
  • +

    URL: /api/v1/admin/sessions/{sessionId}/status

    +
  • +
+
+
+

25.1.1. 요청 예시

+
+
+
PUT /api/v1/admin/conference/5/sessions/5 HTTP/1.1
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEwLCJlbWFpbCI6InRlc3RAZ21haWwuY29tIiwicm9sZSI6IlJPTEVfQURNSU4iLCJpYXQiOjE3NDM0MTIxNzgsImV4cCI6MTc0MzQxMzk3OH0.M-utB9fVEejdRssQd-wDZk2SLAvqEsDZG5c6qN8YceA
+Content-Type: application/x-www-form-urlencoded
+
+
+
+
+
+

25.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 상태 변경 결과

    +
  • +
+
+
+

25.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : "상태가 변경되었습니다.",
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

26. [관리자] 세션 상세 조회 API

+
+
+

관리자가 세션의 상세 정보를 조회하는 API입니다.

+
+
+

26.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/admin/sessions/{sessionId}

    +
  • +
+
+
+

26.1.1. 요청 예시

+
+
+
GET /api/v1/admin/conference/1/sessions/1 HTTP/1.1
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjYsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9BRE1JTiIsImlhdCI6MTc0MzQxMjE3NywiZXhwIjoxNzQzNDEzOTc3fQ.zIoc-CS5nKAz0Ct8EaLiE66QUwzD87_VQnwDNsUeqJw
+
+
+
+
+
+

26.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 세션 상세 정보

    +
  • +
+
+
+

26.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 1,
+    "conferenceId" : 1,
+    "name" : "테스트 세션",
+    "capacity" : 100,
+    "location" : "온라인",
+    "startTime" : "2025-03-31T18:09:37.983881",
+    "endTime" : "2025-03-31T18:09:37.983885",
+    "summary" : "테스트 세션 요약",
+    "speakerName" : "발표자",
+    "speakerOrganization" : "발표자 소속",
+    "isActive" : true,
+    "speakerImage" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+    "speakerStatus" : true
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

27. [관리자] 세션 데이터 수정 API

+
+
+

관리자가 세션의 데이터를 수정하는 API입니다.

+
+
+

27.1. 요청 정보

+
+
    +
  • +

    HTTP Method: PUT

    +
  • +
  • +

    URL: /api/v1/admin/sessions/{sessionId}

    +
  • +
+
+
+

27.1.1. 요청 예시

+
+
+
PUT /api/v1/admin/conference/sessions/3 HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjgsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9BRE1JTiIsImlhdCI6MTc0MzQxMjE3OCwiZXhwIjoxNzQzNDEzOTc4fQ.Aarw_QBvxhiFMZK_CzETb9tybfLWmrk6Q1gOoHhtAxc
+
+{
+  "location" : "변경된 장소"
+}
+
+
+
+
+
+

27.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 수정된 세션 정보

    +
  • +
+
+
+

27.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 3,
+    "conferenceId" : 3,
+    "name" : "테스트 세션",
+    "capacity" : 100,
+    "location" : "변경된 장소",
+    "startTime" : "2025-03-31T18:09:38.064589",
+    "endTime" : "2025-03-31T18:09:38.0646",
+    "summary" : "테스트 세션 요약",
+    "speakerName" : "발표자",
+    "speakerOrganization" : "발표자 소속",
+    "isActive" : true,
+    "speakerImage" : "https://user-faces-storage.s3.ap-northeast-2.amazonaws.com/test.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20250331T090938Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=AKIAYKFQQZLXFVB7FVFI%2F20250331%2Fap-northeast-2%2Fs3%2Faws4_request&X-Amz-Signature=72fa2d2c66db45d687226e9273d4652faf4749b98597b483e86c1de16c67e7ba",
+    "speakerStatus" : true
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

28. 로그인 API

+
+
+

사용자가 이메일과 비밀번호를 통해 로그인하는 API입니다.

+
+
+

28.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/auth/login

    +
  • +
  • +

    Content-Type: application/json

    +
  • +
  • +

    Request Body 필드:

    +
  • +
  • +

    email (필수): 사용자 이메일

    +
  • +
  • +

    password (필수): 사용자 비밀번호

    +
  • +
+
+
+

28.1.1. 요청 예시

+
+
+
POST /api/v1/auth/login HTTP/1.1
+Content-Type: application/json
+
+{
+  "email" : "test@gmail.com",
+  "password" : "1234"
+}
+
+
+
+
+
+

28.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 로그인 성공 시 사용자 정보 및 인증 토큰 반환

    +
  • +
+
+
+

28.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Set-Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjQsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTc3LCJleHAiOjE3NDM0MTM5Nzd9.DOVOwMFk3YZs-Bp3F3ERJPYd-jWPmMiRB4auQHjuvRc; Path=/; Max-Age=1800000; Expires=Mon, 21 Apr 2025 05:09:37 GMT; Secure; HttpOnly; SameSite=None
+Content-Type: application/json
+
+{
+  "data" : {
+    "accessToken" : "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjQsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTc3LCJleHAiOjE3NDM0MTM5Nzd9.DOVOwMFk3YZs-Bp3F3ERJPYd-jWPmMiRB4auQHjuvRc",
+    "id" : 4,
+    "email" : "test@gmail.com",
+    "name" : "홍길순",
+    "phone" : "01011112222",
+    "role" : "USER"
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

29. 로그인 실패 케이스

+
+
+

로그인 시 발생 가능한 실패 응답을 설명합니다.

+
+
+

29.1. 실패 - 이메일 없음

+
+

입력된 이메일이 존재하지 않을 경우입니다.

+
+
+

29.1.1. 요청 예시

+
+
+
POST /api/v1/auth/login HTTP/1.1
+Content-Type: application/json
+
+{
+  "email" : "nonexistent@gmail.com",
+  "password" : "1234"
+}
+
+
+
+
+

29.1.2. 응답 예시

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "로그인 정보에 해당하는 유저가 존재하지 않습니다."
+}
+
+
+
+
+
+
+

29.2. 실패 - 이메일 누락

+
+

이메일을 입력하지 않은 경우입니다.

+
+
+

29.2.1. 요청 예시

+
+
+
POST /api/v1/auth/login HTTP/1.1
+Content-Type: application/json
+
+{
+  "email" : "",
+  "password" : "1234"
+}
+
+
+
+
+

29.2.2. 응답 예시

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "잘못된 요청입니다.",
+  "validationErrors" : [ {
+    "field" : "email",
+    "message" : "이메일을 입력해 주세요."
+  } ]
+}
+
+
+
+
+
+
+

29.3. 실패 - 비밀번호 누락

+
+

비밀번호를 입력하지 않은 경우입니다.

+
+
+

29.3.1. 요청 예시

+
+
+
POST /api/v1/auth/login HTTP/1.1
+Content-Type: application/json
+
+{
+  "email" : "test@gmail.com",
+  "password" : ""
+}
+
+
+
+
+

29.3.2. 응답 예시

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "잘못된 요청입니다.",
+  "validationErrors" : [ {
+    "field" : "password",
+    "message" : "비밀번호를 입력해 주세요."
+  } ]
+}
+
+
+
+
+
+
+

29.4. 실패 - 비밀번호 불일치

+
+

비밀번호가 일치하지 않은 경우입니다.

+
+
+

29.4.1. 요청 예시

+
+
+
POST /api/v1/auth/login HTTP/1.1
+Content-Type: application/json
+
+{
+  "email" : "test@gmail.com",
+  "password" : "wrongpassword"
+}
+
+
+
+
+

29.4.2. 응답 예시

+
+
+
HTTP/1.1 400 Bad Request
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "로그인 정보에 해당하는 유저가 존재하지 않습니다."
+}
+
+
+
+
+
+
+
+

30. 출입 인증 API (컨퍼런스 단위)

+
+
+

QR 토큰을 통해 사용자의 컨퍼런스 출입을 인증하는 API입니다.

+
+
+

30.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/attend/token/conference

    +
  • +
  • +

    Content-Type: application/json

    +
  • +
+
+
+

30.1.1. 요청 예시

+
+
+
GET /api/v1/attend?conferenceId=14 HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjUsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTc2LCJleHAiOjE3NDM0MTM5NzZ9.zgxNCrrFMBkd5QL-1_mUNfjC4HBsCu79c7K1tOb-0ig
+
+
+
+
+
+

30.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 입장 인증 성공 메시지

    +
  • +
+
+
+

30.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 14,
+    "name" : "컨퍼런스B",
+    "description" : "좋은 컨퍼런스B",
+    "location" : "서울 법성포B",
+    "startTime" : "2025-03-31T18:09:36.134725",
+    "endTime" : "2025-03-31T18:09:36.134726",
+    "capacity" : 10,
+    "hasSessions" : false,
+    "imageUrl" : "test.png",
+    "isActive" : true,
+    "sessions" : [ ],
+    "attend" : true
+  },
+  "status" : true
+}
+
+
+
+
+
+
+

30.3. 실패 - 잘못된 컨퍼런스 토큰

+
+

존재하지 않거나 만료된 토큰으로 컨퍼런스 입장 시도 시 발생합니다.

+
+
+

30.3.1. 요청 예시

+
+
+
GET /api/v1/attend?conferenceId=6 HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjIsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTc1LCJleHAiOjE3NDM0MTM5NzV9.9IoCXofhEoSTwUTtWxltCBqC6eqYV1KHzQMZS4rMGEc
+
+
+
+
+

30.3.2. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 6,
+    "name" : "컨퍼런스C",
+    "description" : "좋은 컨퍼런스C",
+    "location" : "서울 법성포C",
+    "startTime" : "2025-03-31T18:09:35.799166",
+    "endTime" : "2025-03-31T18:09:35.799168",
+    "capacity" : 10,
+    "hasSessions" : false,
+    "imageUrl" : "test.png",
+    "isActive" : true,
+    "sessions" : [ ],
+    "attend" : false
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

31. 출입 인증 API (세션 단위)

+
+
+

QR 토큰을 통해 사용자의 세션 출입을 인증하는 API입니다.

+
+
+

31.1. 요청 정보

+
+
    +
  • +

    HTTP Method: POST

    +
  • +
  • +

    URL: /api/v1/attend/token/session

    +
  • +
  • +

    Content-Type: application/json

    +
  • +
+
+
+

31.1.1. 요청 예시

+
+
+
GET /api/v1/attend?conferenceId=1 HTTP/1.1
+Content-Type: application/json
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjEsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTc1LCJleHAiOjE3NDM0MTM5NzV9.YY3nesjlOedfByxlER94JU137PLgmxaS7W5f48FlFDY
+
+
+
+
+
+

31.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 세션 입장 인증 성공 메시지

    +
  • +
+
+
+

31.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "id" : 1,
+    "name" : "컨퍼런스A",
+    "description" : "좋은 컨퍼런스A",
+    "location" : "서울 법성포A",
+    "startTime" : "2025-03-31T18:09:35.14476",
+    "endTime" : "2025-03-31T18:09:35.14477",
+    "capacity" : 10,
+    "hasSessions" : true,
+    "imageUrl" : "test.png",
+    "isActive" : true,
+    "sessions" : [ {
+      "id" : 1,
+      "name" : "세션",
+      "capacity" : 10,
+      "location" : "서울 법성포 떡잎마을",
+      "startTime" : "2025-03-31T18:09:35.156562",
+      "endTime" : "2025-03-31T18:09:35.15657",
+      "summary" : "좋은 세션",
+      "speakerName" : "발표자",
+      "speakerOrganization" : "발표자 소속",
+      "speakerImageKey" : null,
+      "attend" : true,
+      "active" : true
+    } ],
+    "attend" : true
+  },
+  "status" : true
+}
+
+
+
+
+
+
+
+
+

32. 출입 요약 정보 조회 API

+
+
+

사용자의 컨퍼런스 또는 세션 출입 정보를 요약해서 조회하는 API입니다.

+
+
+

32.1. 요청 정보

+
+
    +
  • +

    HTTP Method: GET

    +
  • +
  • +

    URL: /api/v1/attend/summary

    +
  • +
+
+
+

32.1.1. 요청 예시

+
+
+
GET /api/v1/attend/users?conferenceId=10&sessionId=4 HTTP/1.1
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjQsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTc2LCJleHAiOjE3NDM0MTM5NzZ9.jsBEsKqNaxSh5tNwvm8kDp6TGxG2Lgn2FKE7ZmJ-LNc
+
+
+
+
+
+

32.2. 응답 정보

+
+
    +
  • +

    Status: 200 OK

    +
  • +
  • +

    응답 내용: 출입 현황 요약

    +
  • +
+
+
+

32.2.1. 응답 예시

+
+
+
HTTP/1.1 200 OK
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "data" : {
+    "name" : "세션",
+    "capacity" : 10,
+    "attendedCount" : 1,
+    "userAttendances" : [ {
+      "userId" : 4,
+      "userName" : "홍길순",
+      "isAttended" : true
+    } ]
+  },
+  "status" : true
+}
+
+
+
+
+
+
+

32.3. 실패 - 출입 내역 없음

+
+

출입한 이력이 존재하지 않는 경우입니다.

+
+
+

32.3.1. 요청 예시

+
+
+
GET /api/v1/attend/users?conferenceId=999&sessionId=999 HTTP/1.1
+Cookie: Authorization=eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjMsImVtYWlsIjoidGVzdEBnbWFpbC5jb20iLCJyb2xlIjoiUk9MRV9VU0VSIiwiaWF0IjoxNzQzNDEyMTc1LCJleHAiOjE3NDM0MTM5NzV9.CAZ-uW9JhZvnhO4HuobNE0Ul4njXf9vg2fuyimNPkQ4
+
+
+
+
+

32.3.2. 응답 예시

+
+
+
HTTP/1.1 204 No Content
+Vary: Origin
+Vary: Access-Control-Request-Method
+Vary: Access-Control-Request-Headers
+Content-Type: application/json
+
+{
+  "status" : false,
+  "message" : "해당 컨퍼런스/세션 에 참석 유저 데이터가 존재하지 않습니다."
+}
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/static/docs/qr-code.html b/src/main/resources/static/docs/qr-code.html deleted file mode 100644 index 591809d8..00000000 --- a/src/main/resources/static/docs/qr-code.html +++ /dev/null @@ -1,586 +0,0 @@ - - - - - - - -QR 코드 API 명세서 - - - - - -
-
-
-
-

QR 코드를 생성하고 조회하는 API에 대한 명세서입니다.

-
-
-
-
-
-

1. QR 코드 생성 API

-
-
-

QR 코드를 생성하여 URL과 함께 반환합니다. -컨퍼런스 ID와 세션 ID를 기반으로 QR을 생성하며, 세션 ID는 선택값입니다.

-
-
-

1.1. 요청 정보

-
-
    -
  • -

    HTTP Method: GET

    -
  • -
  • -

    URL: /api/v1/admin/qr

    -
  • -
  • -

    Query Parameters:

    -
  • -
  • -

    conferenceId (필수): 컨퍼런스 ID

    -
  • -
  • -

    sessionId (선택): 세션 ID

    -
  • -
  • -

    url (필수): QR에 포함될 URL

    -
  • -
-
-
-

1.1.1. 요청 예시

-
-

Unresolved directive in qr-code.adoc - include::{projectdir}/build/generated-snippets/qr-code-controller-test/qr-code_-create_-success/http-request.adoc[]

-
-
-
-
-

1.2. 응답 정보

-
-
    -
  • -

    Status: 200 OK

    -
  • -
  • -

    응답 내용: QR 코드 정보 반환

    -
  • -
-
-
-

1.2.1. 응답 예시

-
-

Unresolved directive in qr-code.adoc - include::{projectdir}/build/generated-snippets/qr-code-controller-test/qr-code_-create_-success/http-response.adoc[]

-
-
-
-
-
-
-
-

2. 오류 케이스

-
-
-

QR 코드 생성 과정에서 발생할 수 있는 오류 케이스를 설명합니다.

-
-
-
-

2.1. 실패 - 존재하지 않는 Conference ID

-
-

요청한 `conferenceId`가 존재하지 않을 때 발생합니다.

-
-
-

2.1.1. 요청 예시

-
-

Unresolved directive in qr-code.adoc - include::{projectdir}/build/generated-snippets/qr-code-controller-test/qr-code_-conference-id_-not-found/http-request.adoc[]

-
-
-
-

2.1.2. 응답 예시

-
-

Unresolved directive in qr-code.adoc - include::{projectdir}/build/generated-snippets/qr-code-controller-test/qr-code_-conference-id_-not-found/http-response.adoc[]

-
-
-
-
-
-

2.2. 실패 - 존재하지 않는 Session ID

-
-

요청한 `sessionId`가 존재하지 않을 때 발생합니다.

-
-
-

2.2.1. 요청 예시

-
-

Unresolved directive in qr-code.adoc - include::{projectdir}/build/generated-snippets/qr-code-controller-test/qr-code_-session-id_-not-found/http-request.adoc[]

-
-
-
-

2.2.2. 응답 예시

-
-

Unresolved directive in qr-code.adoc - include::{projectdir}/build/generated-snippets/qr-code-controller-test/qr-code_-session-id_-not-found/http-response.adoc[]

-
-
-
-
-
-
- - - \ No newline at end of file diff --git a/src/test/java/goorm/back/zo6/attend/presentation/AttendControllerTest.java b/src/test/java/goorm/back/zo6/attend/presentation/AttendControllerTest.java index 808e99ac..d946cd7c 100644 --- a/src/test/java/goorm/back/zo6/attend/presentation/AttendControllerTest.java +++ b/src/test/java/goorm/back/zo6/attend/presentation/AttendControllerTest.java @@ -14,6 +14,7 @@ import goorm.back.zo6.conference.domain.Session; import goorm.back.zo6.conference.infrastructure.ConferenceJpaRepository; import goorm.back.zo6.conference.infrastructure.SessionJpaRepository; +import goorm.back.zo6.config.RestDocsConfiguration; import goorm.back.zo6.reservation.domain.Reservation; import goorm.back.zo6.reservation.domain.ReservationSession; import goorm.back.zo6.reservation.domain.ReservationStatus; @@ -27,15 +28,21 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; import java.time.LocalDateTime; import java.util.List; @@ -43,16 +50,27 @@ import static org.hamcrest.Matchers.hasSize; import static org.mockito.Mockito.when; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; @SpringBootTest @AutoConfigureMockMvc @Transactional @ActiveProfiles("test") +@ExtendWith(RestDocumentationExtension.class) +@Import(RestDocsConfiguration.class) class AttendControllerTest { + @Autowired + private WebApplicationContext context; + + @Autowired + private RestDocumentationResultHandler restDocs; + @Autowired private MockMvc mockMvc; @@ -105,7 +123,13 @@ class AttendControllerTest { private LocalDateTime localDateTime; @BeforeEach - void setUp() { + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = webAppContextSetup(context) + .apply(springSecurity()) + .apply(documentationConfiguration(restDocumentation)) + .alwaysDo(restDocs) + .build(); + localDateTime = LocalDateTime.now(); testUser = User.builder().name("홍길순").email("test@gmail.com").phone("010-1111-2222").password(Password.from(passwordEncoder.encode("1234"))).role(Role.of("USER")).build(); diff --git a/src/test/java/goorm/back/zo6/auth/presentation/AuthControllerTest.java b/src/test/java/goorm/back/zo6/auth/presentation/AuthControllerTest.java index 8f3577a4..33552dbd 100644 --- a/src/test/java/goorm/back/zo6/auth/presentation/AuthControllerTest.java +++ b/src/test/java/goorm/back/zo6/auth/presentation/AuthControllerTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import goorm.back.zo6.auth.application.AuthService; import goorm.back.zo6.auth.util.JwtUtil; +import goorm.back.zo6.config.RestDocsConfiguration; import goorm.back.zo6.user.domain.Password; import goorm.back.zo6.user.domain.Role; import goorm.back.zo6.user.domain.User; @@ -14,25 +15,42 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; @SpringBootTest @AutoConfigureMockMvc @Transactional @ActiveProfiles("test") +@ExtendWith(RestDocumentationExtension.class) +@Import(RestDocsConfiguration.class) class AuthControllerTest { + + @Autowired + private WebApplicationContext context; + + @Autowired + private RestDocumentationResultHandler restDocs; + @Autowired private MockMvc mockMvc; @@ -57,7 +75,13 @@ class AuthControllerTest { private User testUser; @BeforeEach - void setUp() { + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = webAppContextSetup(context) + .apply(springSecurity()) + .apply(documentationConfiguration(restDocumentation)) + .alwaysDo(restDocs) + .build(); + testUser = User.builder() .name("홍길순") .email("test@gmail.com") diff --git a/src/test/java/goorm/back/zo6/conference/presentation/ConferenceAdminControllerTest.java b/src/test/java/goorm/back/zo6/conference/presentation/ConferenceAdminControllerTest.java index 38a6af60..1150ad3e 100644 --- a/src/test/java/goorm/back/zo6/conference/presentation/ConferenceAdminControllerTest.java +++ b/src/test/java/goorm/back/zo6/conference/presentation/ConferenceAdminControllerTest.java @@ -35,11 +35,11 @@ import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -@ExtendWith({RestDocumentationExtension.class, SpringExtension.class}) @SpringBootTest -@Transactional @AutoConfigureMockMvc +@Transactional @ActiveProfiles("test") +@ExtendWith(RestDocumentationExtension.class) @Import(RestDocsConfiguration.class) public class ConferenceAdminControllerTest { diff --git a/src/test/java/goorm/back/zo6/conference/presentation/ConferenceControllerTest.java b/src/test/java/goorm/back/zo6/conference/presentation/ConferenceControllerTest.java index bd76a2fa..86161d2c 100644 --- a/src/test/java/goorm/back/zo6/conference/presentation/ConferenceControllerTest.java +++ b/src/test/java/goorm/back/zo6/conference/presentation/ConferenceControllerTest.java @@ -23,7 +23,6 @@ import org.springframework.restdocs.RestDocumentationExtension; import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.transaction.annotation.Transactional; @@ -34,11 +33,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -@ExtendWith({RestDocumentationExtension.class, SpringExtension.class}) @SpringBootTest -@Transactional @AutoConfigureMockMvc +@Transactional @ActiveProfiles("test") +@ExtendWith(RestDocumentationExtension.class) @Import(RestDocsConfiguration.class) class ConferenceControllerTest { @@ -114,7 +113,7 @@ void getSessionDetail_ReturnsSpecificSession() throws Exception { .header("Authorization", "Bearer " + testToken)) .andExpect(status().isOk()) .andExpect(jsonPath("$.data.id").value(session.getId())) - .andExpect(jsonPath("$.data.conferenceId").value(session.getId())) + .andExpect(jsonPath("$.data.conferenceId").value(conference.getId())) .andExpect(jsonPath("$.data.name").value(session.getName())) .andExpect(jsonPath("$.data.capacity").value(session.getCapacity())) .andExpect(jsonPath("$.data.location").value(session.getLocation())) diff --git a/src/test/java/goorm/back/zo6/face/presentation/FaceRecognitionControllerTest.java b/src/test/java/goorm/back/zo6/face/presentation/FaceRecognitionControllerTest.java index bcffa246..b87ed5f4 100644 --- a/src/test/java/goorm/back/zo6/face/presentation/FaceRecognitionControllerTest.java +++ b/src/test/java/goorm/back/zo6/face/presentation/FaceRecognitionControllerTest.java @@ -1,10 +1,10 @@ package goorm.back.zo6.face.presentation; import goorm.back.zo6.auth.application.OAuth2LoginSuccessHandlerFactory; -import goorm.back.zo6.auth.config.SecurityConfig; import goorm.back.zo6.auth.util.JwtUtil; import goorm.back.zo6.common.exception.CustomException; import goorm.back.zo6.common.exception.ErrorCode; +import goorm.back.zo6.config.RestDocsConfiguration; import goorm.back.zo6.face.application.FaceRecognitionService; import goorm.back.zo6.face.domain.Face; import goorm.back.zo6.face.dto.response.FaceAuthResultResponse; @@ -14,33 +14,48 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext; import org.springframework.http.MediaType; import org.springframework.mock.web.MockMultipartFile; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; import org.springframework.web.multipart.MultipartFile; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.*; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; @SpringBootTest @AutoConfigureMockMvc @Transactional @ActiveProfiles("test") +@ExtendWith(RestDocumentationExtension.class) +@Import(RestDocsConfiguration.class) class FaceRecognitionControllerTest { + @Autowired + private WebApplicationContext context; + + @Autowired + private RestDocumentationResultHandler restDocs; + @Autowired private MockMvc mockMvc; @@ -60,7 +75,13 @@ class FaceRecognitionControllerTest { private OAuth2UserServiceFactory oAuth2UserServiceFactory; @BeforeEach - void setUp() { + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = webAppContextSetup(context) + .apply(springSecurity()) + .apply(documentationConfiguration(restDocumentation)) + .alwaysDo(restDocs) + .build(); + when(jwtUtil.validateToken(anyString())).thenReturn(true); when(jwtUtil.getUserId(anyString())).thenReturn(1L); when(jwtUtil.getUsername(anyString())).thenReturn("test@example.com"); diff --git a/src/test/java/goorm/back/zo6/reservation/presentation/ReservationControllerTest.java b/src/test/java/goorm/back/zo6/reservation/presentation/ReservationControllerTest.java index 943d1c6a..21cdb4a7 100644 --- a/src/test/java/goorm/back/zo6/reservation/presentation/ReservationControllerTest.java +++ b/src/test/java/goorm/back/zo6/reservation/presentation/ReservationControllerTest.java @@ -12,12 +12,10 @@ import goorm.back.zo6.fixture.ReservationFixture; import goorm.back.zo6.fixture.SessionFixture; import goorm.back.zo6.fixture.UserFixture; -import goorm.back.zo6.reservation.application.ReservationRequest; import goorm.back.zo6.reservation.domain.Reservation; import goorm.back.zo6.reservation.infrastructure.ReservationJpaRepository; import goorm.back.zo6.user.domain.User; import goorm.back.zo6.user.infrastructure.UserJpaRepository; -import jakarta.servlet.http.Cookie; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -49,10 +47,10 @@ @SpringBootTest @AutoConfigureMockMvc +@Transactional @ActiveProfiles("test") @ExtendWith(RestDocumentationExtension.class) @Import(RestDocsConfiguration.class) -@Transactional class ReservationControllerTest { @Autowired diff --git a/src/test/java/goorm/back/zo6/sse/presentation/SseControllerTest.java b/src/test/java/goorm/back/zo6/sse/presentation/SseControllerTest.java index 1c74a928..06d93d6b 100644 --- a/src/test/java/goorm/back/zo6/sse/presentation/SseControllerTest.java +++ b/src/test/java/goorm/back/zo6/sse/presentation/SseControllerTest.java @@ -1,35 +1,63 @@ package goorm.back.zo6.sse.presentation; +import goorm.back.zo6.config.RestDocsConfiguration; import goorm.back.zo6.sse.infrastructure.EmitterRepository; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import static org.hibernate.validator.internal.util.Contracts.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; @SpringBootTest @AutoConfigureMockMvc @Transactional @ActiveProfiles("test") +@ExtendWith(RestDocumentationExtension.class) +@Import(RestDocsConfiguration.class) class SseControllerTest { + @Autowired + private WebApplicationContext context; + + @Autowired + private RestDocumentationResultHandler restDocs; + @Autowired private MockMvc mockMvc; @Autowired private EmitterRepository emitterRepository; + @BeforeEach + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = webAppContextSetup(context) + .apply(springSecurity()) + .apply(documentationConfiguration(restDocumentation)) + .alwaysDo(restDocs) + .build(); + } + @Test @DisplayName("SSE 구독 요청 - SseEmitter 반환 구독 성공") void subscribe_Success() throws Exception { diff --git a/src/test/java/goorm/back/zo6/user/presentation/UserControllerTest.java b/src/test/java/goorm/back/zo6/user/presentation/UserControllerTest.java index 01d763b8..68ccff56 100644 --- a/src/test/java/goorm/back/zo6/user/presentation/UserControllerTest.java +++ b/src/test/java/goorm/back/zo6/user/presentation/UserControllerTest.java @@ -2,8 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import goorm.back.zo6.auth.util.JwtUtil; +import goorm.back.zo6.fixture.UserFixture; import goorm.back.zo6.user.application.UserService; -import goorm.back.zo6.user.domain.Role; import goorm.back.zo6.user.domain.User; import goorm.back.zo6.user.domain.UserRepository; import goorm.back.zo6.user.dto.request.PhoneRequest; @@ -14,29 +14,46 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; +import org.springframework.restdocs.RestDocumentationContextProvider; +import org.springframework.restdocs.RestDocumentationExtension; +import org.springframework.restdocs.mockmvc.RestDocumentationResultHandler; +import org.springframework.web.context.WebApplicationContext; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MockMvc; import org.springframework.transaction.annotation.Transactional; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import java.util.Optional; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; import static org.junit.jupiter.api.Assertions.*; +import goorm.back.zo6.config.RestDocsConfiguration; + @SpringBootTest @AutoConfigureMockMvc @Transactional @ActiveProfiles("test") +@ExtendWith(RestDocumentationExtension.class) +@Import(RestDocsConfiguration.class) class UserControllerTest { @Autowired + private WebApplicationContext context; + + @Autowired + private RestDocumentationResultHandler restDocs; + private MockMvc mockMvc; @Autowired @@ -56,16 +73,15 @@ class UserControllerTest { private User testUser; - - @BeforeEach - void setUp(){ - testUser = User.builder() - .name("홍길순") - .email("test@gmail.com") - .phone("01011112222") - .role(Role.of("USER")) + void setUp(RestDocumentationContextProvider restDocumentation) { + this.mockMvc = webAppContextSetup(context) + .apply(springSecurity()) + .apply(documentationConfiguration(restDocumentation)) + .alwaysDo(restDocs) .build(); + + this.testUser = userJpaRepository.saveAndFlush(UserFixture.유저()); userJpaRepository.saveAndFlush(testUser); } @@ -160,7 +176,7 @@ void signUp_EmailBlankFails() throws Exception { // given SignUpRequest request = new SignUpRequest("홍길동", "", "4321", "01012345678"); - // when & then + // when && then mockMvc.perform(post("/api/v1/users/signup") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request)))