diff --git a/app.json b/app.json index 190584b..a2c492b 100644 --- a/app.json +++ b/app.json @@ -1,52 +1,52 @@ { - "expo": { - "name": "ASSU_FE_RN", - "slug": "ASSU_FE_RN", - "version": "1.0.0", - "orientation": "portrait", - "icon": "./src/shared/assets/images/icon.png", - "scheme": "assufern", - "userInterfaceStyle": "automatic", - "newArchEnabled": true, - "ios": { - "supportsTablet": true - }, - "android": { - "adaptiveIcon": { - "backgroundColor": "#E6F4FE", - "foregroundImage": "./src/shared/assets/images/android-icon-foreground.png", - "backgroundImage": "./src/shared/assets/images/android-icon-background.png", - "monochromeImage": "./src/shared/assets/images/android-icon-monochrome.png" - }, - "edgeToEdgeEnabled": true, - "predictiveBackGestureEnabled": false - }, - "web": { - "bundler": "metro", - "output": "static", - "favicon": "./src/shared/assets/images/favicon.png" - }, - "plugins": [ - "expo-router", - "expo-document-picker", - [ - "expo-splash-screen", - { - "image": "./src/shared/assets/images/splash-icon.png", - "imageWidth": 200, - "resizeMode": "contain", - "backgroundColor": "#ffffff", - "dark": { - "backgroundColor": "#000000" - } - } - ], - "@react-native-community/datetimepicker", - "expo-web-browser" - ], - "experiments": { - "typedRoutes": true, - "reactCompiler": true - } - } + "expo": { + "name": "ASSU_FE_RN", + "slug": "ASSU_FE_RN", + "version": "1.0.0", + "orientation": "portrait", + "icon": "./src/shared/assets/images/icon.png", + "scheme": "assufern", + "userInterfaceStyle": "automatic", + "newArchEnabled": true, + "ios": { + "supportsTablet": true + }, + "android": { + "adaptiveIcon": { + "backgroundColor": "#E6F4FE", + "foregroundImage": "./src/shared/assets/images/android-icon-foreground.png", + "backgroundImage": "./src/shared/assets/images/android-icon-background.png", + "monochromeImage": "./src/shared/assets/images/android-icon-monochrome.png" + }, + "edgeToEdgeEnabled": true, + "predictiveBackGestureEnabled": false + }, + "web": { + "bundler": "metro", + "output": "static", + "favicon": "./src/shared/assets/images/favicon.png" + }, + "plugins": [ + "expo-router", + "expo-document-picker", + [ + "expo-splash-screen", + { + "image": "./src/shared/assets/images/splash-icon.png", + "imageWidth": 200, + "resizeMode": "contain", + "backgroundColor": "#ffffff", + "dark": { + "backgroundColor": "#000000" + } + } + ], + "@react-native-community/datetimepicker", + "expo-web-browser" + ], + "experiments": { + "typedRoutes": true, + "reactCompiler": true + } + } } diff --git a/openapi/oepnapi.json b/openapi/oepnapi.json index 13a6183..54c2cd9 100644 --- a/openapi/oepnapi.json +++ b/openapi/oepnapi.json @@ -1,6706 +1,6353 @@ { - "openapi": "3.1.0", - "info": { - "title": "ASSU API", - "description": "ASSU API 명세서", - "version": "1.0.0" - }, - "servers": [ - { - "url": "/" - } - ], - "security": [ - { - "JWT TOKEN": [] - } - ], - "tags": [ - { - "name": "Map", - "description": "지도 API" - }, - { - "name": "Review", - "description": "리뷰 API" - }, - { - "name": "Certification", - "description": "QR인증 API" - }, - { - "name": "Auth", - "description": "인증/인가 API" - }, - { - "name": "Report", - "description": "신고 API" - }, - { - "name": "Device Token", - "description": "디바이스 토큰 API" - }, - { - "name": "Admin", - "description": "관리자 API" - }, - { - "name": "Inquiry", - "description": "문의 API" - }, - { - "name": "App Review", - "description": "앱 리뷰 API" - }, - { - "name": "Store", - "description": "가게 API" - }, - { - "name": "Suggestion", - "description": "제휴 건의 API" - }, - { - "name": "Chatting", - "description": "채팅 API" - }, - { - "name": "Admin Dashboard", - "description": "관리자 대시보드 및 통계 API" - }, - { - "name": "Member", - "description": "멤버 API" - }, - { - "name": "Partner", - "description": "제휴업체 API" - }, - { - "name": "Student", - "description": "학생 API" - }, - { - "name": "Notification", - "description": "알림 API" - }, - { - "name": "Partnership", - "description": "제휴 제안 API" - }, - { - "name": "Temp QR", - "description": "임시 QR 인증 API" - } - ], - "paths": { - "/notifications/{type}": { - "put": { - "tags": [ - "Notification" - ], - "summary": "알림 유형별 ON/OFF 토글 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/on-off-2511197c19ed80aeb4eed3c502691361?source=copy_link)\n- 토글 형식으로 유형별 알림을 ON/OFF 합니다.\n- 그룹 토글 기능을 지원합니다.\n\n**Path Variable:**\n- `type` (NotificationType, required): 알림 유형\n - 개별 유형: CHAT, PARTNER_SUGGESTION, PARTNER_PROPOSAL, ORDER, STAMP\n - 그룹 유형: PARTNER_ALL (CHAT + ORDER), ADMIN_ALL (CHAT + PARTNER_SUGGESTION + PARTNER_PROPOSAL)\n\n**Response:**\n- 성공 시 200(OK)와 변경된 알림 설정 상태 반환\n- 400(BAD_REQUEST): 지원하지 않는 알림 유형\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", - "operationId": "toggle", - "parameters": [ - { - "name": "type", - "in": "path", - "required": true, - "schema": { - "type": "string", - "enum": [ - "CHAT", - "PARTNER_SUGGESTION", - "PARTNER_PROPOSAL", - "ORDER", - "PARTNER_ALL", - "ADMIN_ALL", - "STAMP" - ] - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseNotificationSettingsResponseDTO" - } - } - } - } - } - } - }, - "/members/me/profile-image": { - "get": { - "tags": [ - "Member" - ], - "summary": "프로필 이미지 조회 API", - "description": "# [v1.0 (2025-09-18)](https://clumsy-seeder-416.notion.site/2711197c19ed8039bbe2c48380c9f4c8?source=copy_link)\n- 로그인한 사용자의 프로필 이미지 presigned URL을 반환합니다.\n- 반환된 URL은 일정 시간 동안만 유효합니다.\n- 프로필 이미지가 없는 경우 null 반환\n\n**Response:**\n- 성공 시 200(OK)와 presigned URL 반환\n- URL 유효 시간: 10분\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 500(INTERNAL_SERVER_ERROR): S3 presigned URL 생성 실패", - "operationId": "getProfileImage", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseProfileImageResponseDTO" - } - } - } - } - } - }, - "put": { - "tags": [ - "Member" - ], - "summary": "프로필 이미지 업로드/교체 API", - "description": "# [v1.0 (2025-09-15)](https://clumsy-seeder-416.notion.site/26f1197c19ed8031bc50e3571e8ea18f?source=copy_link)\n- `multipart/form-data`로 프로필 이미지를 업로드합니다.\n- 기존 이미지가 있으면 S3에서 삭제 후 새 이미지로 교체합니다.\n\n**Request Parts:**\n- `image` (MultipartFile, required): 프로필 이미지 파일\n - 지원 형식: JPG, PNG, WEBP 등\n - 최대 파일 크기 제한 있음\n\n**Response:**\n- 성공 시 200(OK)와 업로드된 이미지 key 반환\n- 400(BAD_REQUEST): 지원하지 않는 파일 형식 또는 파일 크기 초과\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 500(INTERNAL_SERVER_ERROR): S3 업로드 실패", - "operationId": "uploadOrReplaceProfileImage", - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "image": { - "type": "string", - "format": "binary", - "description": "프로필 이미지 파일 (jpg/png/webp 등)" - } - }, - "required": [ - "image" - ] - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseProfileImageResponseDTO" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Member" - ], - "summary": "프로필 이미지 삭제 API", - "description": "# [v1.0 (2025-09-18)](https://clumsy-seeder-416.notion.site/2dc1197c19ed809cb813f74a1b4c5c26?source=copy_link)\n- 로그인한 사용자의 프로필 이미지를 삭제합니다.\n- S3에서 이미지 파일을 완전히 삭제합니다.\n- 삭제 후 프론트에서 기본 이미지를 표시합니다.\n\n**Response:**\n- 성공 시 200(OK)와 성공 메시지 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 404(NOT_FOUND): 삭제할 프로필 이미지가 없음\n- 500(INTERNAL_SERVER_ERROR): S3 삭제 실패", - "operationId": "deleteProfileImage", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseString" - } - } - } - } - } - } - }, - "/temporary-qr/data": { - "post": { - "tags": [ - "Temp QR" - ], - "summary": "QR 데이터 삽입 API", - "description": "# # [v1.0 (2026-02-14)](https://clumsy-seeder-416.notion.site/QR-3071197c19ed8079aeb9d0555b9e899f?source=copy_link)\n- 임시 QR 적립 데이터를 저장합니다.\n- 요청 바디(JSON)를 통해 QR 적립 대상 정보를 전달합니다.\n\n**Request Body:**\n - `adminName` (String, required): 학생회(관리자) 이름 (ex. 컴퓨터학부 학생회, 총학생회, IT대 학생회)\n - `sort` (Enum, required): 어떻게 적립되었는지 REVIEW/SUGGEST 중 하나 입력\n\n**Response:**\n - 성공 시 200(OK)\n", - "operationId": "insertQrData", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TemporaryQrRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/suggestion": { - "post": { - "tags": [ - "Suggestion" - ], - "summary": "제휴 건의 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-2241197c19ed81e68840d565af59b534)\n- 현재 로그인한 학생이 관리자에게 제휴를 건의합니다.\n- 성공 시 200(OK)과 Suggestion 객체 반환.\n\n**Request Body:**\n - `suggestionRequest` 객체 (JSON, required)\n - `adminId` (Long): 건의 대상 관리자 ID\n - `storeName` (String): 희망 가게 이름\n - `benefit` (String): 희망 혜택\n\n**Response:**\n - `suggestionId` (Long): 건의 ID\n - `userId` (Long): 제안인 ID\n - `adminId` (Long): 건의 대상 관리자 ID\n - `storeName` (String): 희망 가게 이름\n - `suggestionBenefit` (String): 희망 혜택\n", - "operationId": "writeSuggestion", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/WriteSuggestionRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseWriteSuggestionResponseDTO" - } - } - } - } - } - } - }, - "/students/sync/all": { - "post": { - "tags": [ - "Student" - ], - "summary": "전체 학생의 사용 가능 제휴 동기화 API", - "description": "# [v1.0 (2026-03-16)](https://clumsy-seeder-416.notion.site/3251197c19ed8066885cece9ffc455f6?source=copy_link)\n- 모든 학생의 user_paper 데이터를 동기화합니다.\n- 관리자 전용 API입니다.\n- 시스템 전체에 영향을 주는 작업이므로 주의해서 사용해야 합니다.\n\n**주의사항:**\n- 대량의 데이터 처리로 인해 시간이 오래 걸릴 수 있음\n- 실행 중에는 다른 제휴 관련 작업에 영향을 줄 수 있음\n\n**Response:**\n- 성공 시 200(OK)와 동기화 완료 메시지 반환\n- 403(FORBIDDEN): 관리자 권한 없음\n- 500(INTERNAL_SERVER_ERROR): 동기화 작업 실패", - "operationId": "syncAllStudentsNow", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseString" - } - } - } - } - } - } - }, - "/students/stamp": { - "get": { - "tags": [ - "Student" - ], - "summary": "사용자 스탬프 개수 조회 API", - "description": "# [v1.0 (2025-09-09)](https://www.notion.so/2691197c19ed805c980dd546adee9301?source=copy_link)\n- `multipart/form-data`로 호출합니다.\n- login 필요 \n**Response:**\n - stamp 개수 반환 \n", - "operationId": "getStamp", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCheckStampResponseDTO" - } - } - } - } - } - }, - "post": { - "tags": [ - "Student" - ], - "summary": "스탬프 적립 및 이벤트 응모 API", - "description": "# [v1.0 (2026-02-23)](https://clumsy-seeder-416.notion.site/3101197c19ed80b5b47eceb202535469)\n- 스탬프가 10개가 되는 시점에 자동으로 응모및 알림", - "operationId": "earnStamp", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseString" - } - } - } - } - } - } - }, - "/reviews": { - "post": { - "tags": [ - "Review" - ], - "summary": "리뷰 작성 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2241197c19ed8176ba4fcb49c0136f93)\n- 리뷰 내용, 별점, 이미지를 멀티파트로 입력받아 저장합니다.\n- Authentication: JWT 토큰 필요 (Student 권한)", - "operationId": "writeReview", - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "request": { - "$ref": "#/components/schemas/WriteReviewRequestDTO" - }, - "reviewImages": { - "type": "array", - "items": { - "type": "string", - "format": "binary" - } - } - }, - "required": [ - "request" - ] - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseWriteReviewResponseDTO" - } - } - } - } - } - } - }, - "/reports": { - "post": { - "tags": [ - "Report" - ], - "summary": "콘텐츠 신고 API", - "description": "# [v1.0 (2025-09-24)](https://clumsy-seeder-416.notion.site/API-2771197c19ed80b79afbf3d8d8d82c15?source=copy_link)\n- 신고자는 본인 Member ID로 자동 설정됩니다.\n- 자기 자신의 콘텐츠를 신고할 수 없습니다.\n- 동일한 대상을 중복 신고할 수 없습니다.\n\n**Request Body:**\n- `targetType` (ReportTargetType enum, required): 신고 대상 타입 (REVIEW, SUGGESTION)\n- `targetId` (Long, required): 리뷰 ID 또는 건의글 ID\n- `reportType` (ReportType enum, required): 신고 유형\n - 리뷰 신고: REVIEW_INAPPROPRIATE_CONTENT, REVIEW_FALSE_INFORMATION, REVIEW_SPAM\n - 건의글 신고: SUGGESTION_INAPPROPRIATE_CONTENT, SUGGESTION_FALSE_INFORMATION, SUGGESTION_SPAM\n\n**Response:**\n- 성공 시 201(CREATED)과 신고 ID 반환", - "operationId": "reportContent", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateContentReportRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCreateReportResponse" - } - } - } - } - } - } - }, - "/reports/students": { - "post": { - "tags": [ - "Report" - ], - "summary": "작성자 신고 API", - "description": "# [v1.0 (2025-09-24)](https://clumsy-seeder-416.notion.site/API-2771197c19ed80f8ab45e70772fcfc58?source=copy_link)\n- 신고자는 본인 Member ID로 자동 설정됩니다.\n- 자기 자신을 신고할 수 없습니다.\n- 동일한 작성자를 중복 신고할 수 없습니다.\n\n**Request Body:**\n- `targetType` (ReportTargetType enum, required): 신고 대상 타입 (REVIEW, SUGGESTION)\n- `targetId` (Long, required): 리뷰 ID 또는 건의글 ID\n- `reportType` (ReportType enum, required): 신고 유형\n - 사용자 신고: STUDENT_USER_SPAM, STUDENT_USER_INAPPROPRIATE_CONTENT, STUDENT_USER_HARASSMENT, STUDENT_USER_FRAUD, STUDENT_USER_PRIVACY_VIOLATION, STUDENT_USER_OTHER\n\n**Response:**\n- 성공 시 201(CREATED)과 신고 ID 반환", - "operationId": "reportStudent", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStudentReportRequest" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCreateReportResponse" - } - } - } - } - } - } - }, - "/partnership/usage": { - "post": { - "tags": [ - "Partnership" - ], - "summary": "제휴 사용내역 기록 API", - "description": "# [v1.0 (2025-12-23)](https://clumsy-seeder-416.notion.site/2681197c19ed8052804eddd5a1f3ce96?source=copy_link)\n- 제휴 제공 화면 전에 호출되어 유저의 제휴 내역에 데이터를 기록합니다.\n- 인증 이후 제휴를 받았다는 때 서버의 데이터 기록을 요청하는 API \n- 개인 인증 케이스도 포함됩니다.\n\n**Request Body:**\n - `storeId` (Long, required): 제휴 매장 ID\n - `tableNumber` (String, required): 테이블 번호\n - `adminName` (String, required): 관리자 이름\n - `placeName` (String, required): 제휴 장소 이름\n - `partnershipContent` (String, required): 제휴 내용\n - `contentId` (Long, required): 제휴 컨텐츠 ID\n - `discount` (Long, optional): 할인 금액\n - `userIds` (List, optional): 인증 대상 유저 ID 목록\n\n**Response:**\n - 성공: 200 OK, `isSuccess=true`, `result=null`\n - 실패: 적절한 에러 코드 및 메시지", - "operationId": "finalPartnershipRequest", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PartnershipFinalRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/partnership/proposal/draft": { - "post": { - "tags": [ - "Partnership" - ], - "summary": "제휴 제안서 초안 생성 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed8043a511cc8ea005d5b4)\n- 관리자로 로그인한 상태에서 제안서 초안을 생성합니다.\n- 제안서를 작성할 제휴업체 ID 입력.\n\n**Request Body:**\n - `CreateDraftRequest` 객체 (JSON, required)\n - `partnerId` (Long): 제휴 제안서를 작성할 제휴업체 ID\n\n**Response:**\n - 성공 시 200(OK)과 `CreateDraftResponse` 객체 반환.\n - `paperId` (Long): 생성된 제안서 ID\n", - "operationId": "createDraftPartnership", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PartnershipDraftRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePartnershipDraftResponseDTO" - } - } - } - } - } - } - }, - "/partnership/passivity": { - "post": { - "tags": [ - "Partnership" - ], - "summary": "제휴 제안서 수동 등록 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed804785d9f58f95223048)\n- 관리자로 로그인한 상황에서 내용이 있는 제휴 제안서를 생성합니다.\n- 계약서 이미지 MultipartFile을 입력.\n- 주소 입력 시 장소 검색용 API에서 반환된 Map 객체의 내용을 selectedPlace에 입력.\n- options의 optionType을 SERVICE/DISCOUNT 중 하나로 설정.\n- options의 criterionType을 PRICE/HEADCOUNT 중 하나로 설정.\n- 이외의 제휴 유형일 경우 anotherType을 true로 설정.\n- DB에 해당하는 store가 없다면 생성.\n- 해당하는 store가 INACTIVE 상태였다면 ACTIVE 상태로 변환.\n\n**Request Body:**\n - `ManualPartnershipRequest` 객체 (JSON, required): 제안서 내용\n - `storeName` (String): 가게 이름\n - `selectedPlace` (JSON): 선택된 장소\n - `placeId` (String): kakao place ID\n - `name` (String): kakao place 이름\n - `address` (String): 지번 주소\n - `roadAddress` (String): 도로명 주소\n - `latitude` (Double): 장소 위도\n - `longitude` (Double): 장소 경도\n - `storeDetailAddress` (String): 가게 상세주소\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `goods` (JSON): 서비스 제공 항목\n - `goodsName` (String): 서비스 제공 항목명\n - `contractImage` (MultipartFile, required): 계약서 이미지 파일\n\n**Response:**\n - 성공 시 200(OK)과 `ManualPartnershipResponse` 객체 반환.\n - `storeId` (Long): 가게 ID\n - `storeCreated` (boolean): 가게가 DB에 생성되었는지 여부\n - `storeActivated` (boolean): 가게가 재활성화되었는지 여부\n - `status` (String): 제휴 제안서의 상태\n - `contractImageUrl` (String): 계약서 파일 URL\n - `partnership` (JSON): 제휴 제안서\n - `partnershipId` (Long): 제안서 ID\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `storeName` (String): 가게 이름\n - `adminName` (String): 관리자 이름\n - `isActivated` (ActivationStatus): 제안서 활성화 여부\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", - "operationId": "createManualPartnership", - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "request": { - "$ref": "#/components/schemas/ManualPartnershipRequestDTO" - }, - "contractImage": { - "type": "string", - "format": "binary", - "description": "계약서 이미지 파일" - } - }, - "required": [ - "contractImage", - "request" - ] - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseManualPartnershipResponseDTO" - } - } - } - } - } - } - }, - "/notifications/{notificationId}/read": { - "post": { - "tags": [ - "Notification" - ], - "summary": "알림 읽음 처리 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2491197c19ed80a89ff0c03bc150460f?source=copy_link)\n- 알림 ID에 해당하는 알림을 읽음 처리합니다.\n- 본인의 알림만 읽음 처리 가능합니다.\n\n**Path Variable:**\n- `notificationId` (Long, required): 알림 ID\n\n**Response:**\n- 성공 시 200(OK)과 성공 메시지 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 403(FORBIDDEN): 다른 사용자의 알림 접근 시도\n- 404(NOT_FOUND): 존재하지 않는 알림 ID\n- 409(CONFLICT): 이미 읽음 처리된 알림", - "operationId": "markRead", - "parameters": [ - { - "name": "notificationId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseString" - } - } - } - } - } - } - }, - "/notifications/queue": { - "post": { - "tags": [ - "Notification" - ], - "summary": "알림 전송 테스트 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2511197c19ed8051bc93d95f0b216543?source=copy_link)\n- 알림 전송 기능을 테스트합니다.\n- 디바이스 토큰을 등록한 이후에 사용 가능합니다.\n\n**Request Body:**\n- `memberId` (Long, required): 대상 멤버 ID\n- `title` (String, required): 알림 제목\n- `body` (String, required): 알림 내용\n\n**Response:**\n- 성공 시 200(OK)과 성공 메시지 반환\n- 400(BAD_REQUEST): 필수 필드 누락\n- 404(NOT_FOUND): 존재하지 않는 멤버 ID 또는 디바이스 토큰 없음\n- 500(INTERNAL_SERVER_ERROR): FCM 전송 실패", - "operationId": "queue", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueueNotificationRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseString" - } - } - } - } - } - } - }, - "/inquiries": { - "get": { - "tags": [ - "Inquiry" - ], - "summary": "문의 내역 목록 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2441197c19ed803eba4af9598484e5c5?source=copy_link)\n- 본인의 문의 내역 목록을 상태별로 조회합니다.\n\n**Request Parameters:**\n- `status` (String, optional): 문의 상태 (WAITING, ANSWERED, ALL) - 기본값: ALL\n- `page` (Integer, optional): 페이지 번호 (1 이상) - 기본값: 1\n- `size` (Integer, optional): 페이지 크기 - 기본값: 20\n\n**Response:**\n- 성공 시 200(OK)과 문의 목록 반환\n- 400(BAD_REQUEST): 잘못된 페이지 번호 또는 상태 값\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", - "operationId": "list", - "parameters": [ - { - "name": "status", - "in": "query", - "required": false, - "schema": { - "type": "string", - "default": "ALL", - "enum": [ - "WAITING", - "ANSWERED", - "ALL" - ] - } - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "format": "int32", - "default": 1, - "minimum": 1 - } - }, - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePageResponseDTOInquiryResponseDTO" - } - } - } - } - } - }, - "post": { - "tags": [ - "Inquiry" - ], - "summary": "문의하기 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2441197c19ed800688f0cfb304dead63?source=copy_link)\n- 문의를 생성하고 해당 문의의 ID를 반환합니다.\n\n**Request Body:**\n- `title` (String, required): 문의 제목\n- `content` (String, required): 문의 내용\n- `email` (String, required): 답변 받을 이메일\n\n**Response:**\n- 성공 시 200(OK)과 생성된 문의 ID 반환\n- 400(BAD_REQUEST): 필수 필드 누락 또는 잘못된 이메일 형식\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", - "operationId": "create", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InquiryCreateRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseLong" - } - } - } - } - } - } - }, - "/device-tokens": { - "post": { - "tags": [ - "Device Token" - ], - "summary": "디바이스 토큰 등록 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed8092864ac5a1ddc88d07?source=copy_link)\n- 디바이스 토큰을 등록하고 등록된 토큰의 ID를 반환합니다.\n- 푸시 알림 수신을 위해 필수로 등록해야 합니다.\n\n**Request Parameters:**\n- `token` (String, required): FCM 디바이스 토큰\n\n**Response:**\n- 성공 시 200(OK)과 등록된 토큰 ID 반환\n- 400(BAD_REQUEST): 빈 토큰 또는 잘못된 토큰 형식\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 409(CONFLICT): 이미 등록된 토큰", - "operationId": "register", - "parameters": [ - { - "name": "token", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseLong" - } - } - } - } - } - } - }, - "/chat/rooms": { - "get": { - "tags": [ - "Chatting" - ], - "summary": "채팅방 목록 조회 API", - "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/API-1d71197c19ed819f8f70fb437e9ce62b?p=2241197c19ed816993c3c5ae17d6f099&pm=s)\n- 채팅방 목록을 조회합니다.\n", - "operationId": "getChatRoomList", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseListChatRoomListResultDTO" - } - } - } - } - } - }, - "post": { - "tags": [ - "Chatting" - ], - "summary": "채팅방 생성 API", - "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed80c38871ec77deced713)\n- 채팅방을 생성합니다.\n\n**Request Body:**\n- adminId (Long, required): 관리자 ID\n- partnerId (Long, required) 제휴업체 ID\n", - "operationId": "createChatRoom", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateChatRoomRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCreateChatRoomResponseDTO" - } - } - } - } - } - } - }, - "/chat/block": { - "post": { - "tags": [ - "Chatting" - ], - "summary": "상대방 차단 API", - "description": "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed804ba3dbf57ba36860c4)\n- 상대방을 차단합니다.\n- 메시지를 주고받을 수 없습니다.\n\n**Request Body:**\n- opponentId (Long, required): 상대방 ID\n", - "operationId": "block", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BlockMemberRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseBlockMemberDTO" - } - } - } - } - } - } - }, - "/certification/session": { - "post": { - "tags": [ - "Certification" - ], - "summary": "세션 정보 요청 API", - "description": "# [v1.0 (2025-09-09)](https://www.notion.so/22b1197c19ed80bb8484d99cc6ce715b?source=copy_link)\n- `multipart/form-data`로 호출합니다.\n- 파트: `payload`(JSON, CertificationRequest.groupRequest)\n- 처리: 정보 바탕으로 sessionManager에 session생성\n- 성공 시 201(Created)과 생성된 memberId 반환.\n\n**Request Parts:**\n - `request` (JSON, required): `CertificationRequest.groupRequest` 객체\n - `people` (Integer, required): 인증이 필요한 인원\n - `storeId` (Long, required): 스토어 id\n - `adminId` (Long, required): 관리자 id\n - `tableNumber` (Integer, required): 테이블 넘버\n\n**Response:**\n - 성공 시 201(Created)와 sessionId, adminId 반환", - "operationId": "getSessionId", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CertificationGroupRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCertificationResponseDTO" - } - } - } - } - } - } - }, - "/certification/personal": { - "post": { - "tags": [ - "Certification" - ], - "summary": "개인 인증 요청 API", - "description": "# [v1.0 (2025-09-09)](https://clumsy-seeder-416.notion.site/2471197c19ed80fd9a8dcc43fb938a5d?source=copy_link)\n- 개인 단위 인증을 위한 API입니다.\n- 그룹 인증이 아닌 경우, 통계 및 제휴 이력 적재를 목적으로 사용됩니다.\n- 가게별 제휴 조회 시 `people` 값이 null 인 경우 호출됩니다.\n\n**Request Body:**\n - `storeId` (Long, required): 인증이 발생한 스토어 ID\n - `adminId` (Long, required): 인증을 요청한 관리자 ID\n - `tableNumber` (Integer, required): 인증이 발생한 테이블 번호\n\n**Authentication:**\n - 로그인된 사용자 인증 정보 필요 (`@AuthenticationPrincipal`)\n\n**Processing:**\n - 전달받은 정보 기반으로 개인 인증 이력 저장\n - 세션 생성은 하지 않음\n\n**Response:**\n - 성공 시 200(OK)\n - 성공 메시지 반환", - "operationId": "personalCertification", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CertificationPersonalRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseString" - } - } - } - } - } - } - }, - "/auth/tokens/refresh": { - "post": { - "tags": [ - "Auth" - ], - "summary": "Access Token 갱신 API", - "description": "# [v1.0 (2025-09-03)](https://clumsy-seeder-416.notion.site/2501197c19ed806ea8cff29f9cd8695a?source=copy_link)\n- 헤더로 호출합니다.\n- 헤더: `RefreshToken: `.\n- 처리: Refresh 검증/회전 후 신규 Access/Refresh 발급 및 저장.\n- 성공 시 200(OK)과 신규 토큰 반환.\n\n**Headers:**\n - `RefreshToken` (String, required): 리프레시 토큰\n\n**Response:**\n - 성공 시 200(OK)과 `RefreshResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `newAccess` (String): 새로운 액세스 토큰\n - `newRefresh` (String): 새로운 리프레시 토큰", - "operationId": "refreshToken", - "parameters": [ - { - "name": "RefreshToken", - "in": "header", - "description": "Refresh Token", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseRefreshResponseDTO" - } - } - } - } - } - } - }, - "/auth/students/ssu-verify": { - "post": { - "tags": [ - "Auth" - ], - "summary": "숭실대 유세인트 인증 API", - "description": "# [v1.0 (2025-09-03)](https://clumsy-seeder-416.notion.site/23a1197c19ed808d9266e641e5c4ea14?source=copy_link)\n- `application/json`으로 호출합니다.\n\n**Request Body:**\n - `sToken` (String, required): 유세인트 sToken\n - `sIdno` (String, required): 유세인트 sIdno\n- 처리 순서:\n 1) 유세인트 SSO 로그인 시도 (sToken, sIdno 검증)\n 2) 응답 Body 검증 후 세션 쿠키 추출\n 3) 유세인트 포털 페이지 접근 및 HTML 파싱\n 4) 이름, 학번, 소속, 학적 상태, 학년/학기 정보 추출\n 5) 소속 문자열을 전공 Enum(`Major`)으로 매핑\n 6) 인증 결과를 `USaintAuthResponseDTO`로 반환\n\n**Response:**\n - 성공 시 200(OK)과 `USaintAuthResponseDTO` 객체 반환\n - `studentNumber` (String): 학번\n - `name` (String): 이름\n - `enrollmentStatus` (String): 학적 상태\n - `yearSemester` (String): 학년/학기\n - `major` (Major enum): 전공/학과", - "operationId": "ssuAuth", - "requestBody": { - "description": "유세인트 인증 요청", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/USaintAuthRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseUSaintAuthResponseDTO" - } - } - } - } - } - } - }, - "/auth/students/signup": { - "post": { - "tags": [ - "Auth" - ], - "summary": "학생 회원가입 API", - "description": "# [v1.3 (2026-04-02)](https://clumsy-seeder-416.notion.site/2241197c19ed81129c85cf5bbe1f7971)\n- `application/json` 요청 바디를 사용합니다.\n- 처리: 유세인트 인증 → 학생 정보 추출 → 회원가입 완료\n- 성공 시 200(OK)과 생성된 memberId, JWT 토큰, 기본 정보 반환.\n\n**Request Body:**\n - `StudentTokenSignUpRequestDTO` 객체 (JSON, required): 숭실대 학생 토큰 가입 정보\n - `marketingAgree` (Boolean, required): 마케팅 수신 동의\n - `locationAgree` (Boolean, required): 위치 정보 수집 동의\n - `studentTokenAuth` (StudentTokenAuthPayloadDTO, Object, required): 유세인트 토큰 정보\n - `sToken` (String, required): 유세인트 sToken\n - `sIdno` (String, required): 유세인트 sIdno\n - `university` (University enum, required): 대학 이름 (SSU)\n\n**Response:**\n - 성공 시 200(OK)과 `SignUpResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (STUDENT)\n - `status` (ActivationStatus): 회원 상태 (ACTIVE)\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 학생 이름\n - `university` (String): 대학교 (한글명)\n - `department` (String): 단과대 (한글명)\n - `major` (String): 전공/학과 (한글명)", - "operationId": "signupStudent", - "requestBody": { - "description": "JSON 형식의 학생 유저 가입 정보", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StudentTokenSignUpRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseSignUpResponseDTO" - } - } - } - } - } - } - }, - "/auth/students/login": { - "post": { - "tags": [ - "Auth" - ], - "summary": "학생 로그인 API", - "description": "# [v1.2 (2025-09-13)](https://clumsy-seeder-416.notion.site/2501197c19ed80f6b495fa37f8c084a8)\n- `application/json`로 호출합니다.\n- 바디: `StudentTokenAuthPayloadDTO(sToken, sIdno, university)`.\n- 처리: 유세인트 인증 → 기존 회원 확인 → JWT 토큰 발급.\n- 성공 시 200(OK)과 토큰(accessToken/refreshToken), 기본 정보 반환.\n\n**Request Body:**\n - `StudentTokenAuthPayloadDTO` 객체 (JSON, required): 숭실대 학생 토큰 로그인 정보\n - `sToken` (String, required): 유세인트 sToken\n - `sIdno` (String, required): 유세인트 sIdno\n - `university` (University enum, required): 대학 이름 (SSU)\n\n**Response:**\n - 성공 시 200(OK)과 `LoginResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (STUDENT)\n - `status` (ActivationStatus): 회원 상태\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 학생 이름\n - `university` (String): 대학교 (한글명)\n - `department` (String): 단과대 (한글명)\n - `major` (String): 전공/학과 (한글명)", - "operationId": "loginStudent", - "requestBody": { - "description": "학생 토큰 로그인 요청", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StudentTokenAuthPayloadDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseLoginResponseDTO" - } - } - } - } - } - } - }, - "/auth/phone-verification/verify": { - "post": { - "tags": [ - "Auth" - ], - "summary": "휴대폰 인증번호 검증 API", - "description": "# [v1.0 (2025-09-03)](https://clumsy-seeder-416.notion.site/2241197c19ed81bb8c05d9061c0306c0?source=copy_link)\n- 발송된 인증번호(OTP)를 검증합니다.\n\n**Request Body:**\n - `phoneNumber` (String, required): 인증받을 휴대폰 번호\n - `authNumber` (String, required): 발송받은 인증번호(OTP)\n\n**Response:**\n - 성공 시 200(OK)과 성공 메시지 반환", - "operationId": "checkAuthNumber", - "requestBody": { - "description": "휴대폰 인증번호 검증 요청", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PhoneAuthVerifyRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/auth/phone-verification/check-and-send": { - "post": { - "tags": [ - "Auth" - ], - "summary": "휴대폰 번호 중복가입 확인 및 인증번호 발송 API", - "description": "# [v1.1 (2025-09-25)](https://clumsy-seeder-416.notion.site/2241197c19ed801bbcd9f61c3e5f5457?source=copy_link)\n- 입력한 휴대폰 번호로 1회용 인증번호(OTP)를 발송합니다.\n- 중복된 전화번호가 있으면 에러를 반환합니다.\n- 관리자와 제휴업체의 회원가입 이전에 사용하여 전화번호를 검증합니다.\n- 유효시간/재요청 제한 정책은 서버 설정에 따릅니다.\n\n**Request Body:**\n - `phoneNumber` (String, required): 인증번호를 받을 휴대폰 번호\n\n**Response:**\n - 성공 시 200(OK)과 성공 메시지 반환", - "operationId": "checkPhoneAvailabilityAndSendAuthNumber", - "requestBody": { - "description": "휴대폰 인증번호 발송 요청", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PhoneAuthSendRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/auth/partners/signup": { - "post": { - "tags": [ - "Auth" - ], - "summary": "제휴업체 회원가입 API", - "description": "# [v1.2 (2025-09-13)](https://clumsy-seeder-416.notion.site/2501197c19ed80d7a8f2c3a6fcd8b537)\n- `multipart/form-data`로 호출합니다.\n- 파트: `request`(JSON, PartnerSignUpRequestDTO) + `licenseImage`(파일, 사업자등록증).\n- 처리: users + common_auth 생성, 이메일 중복/비밀번호 규칙 검증.\n- 성공 시 200(OK)과 생성된 memberId, JWT 토큰, 기본 정보 반환.\n\n**Request Parts:**\n - `request` (JSON, required): `PartnerSignUpRequestDTO` 객체\n - `phoneNumber` (String, required): 휴대폰 번호\n - `marketingAgree` (Boolean, required): 마케팅 수신 동의\n - `locationAgree` (Boolean, required): 위치 정보 수집 동의\n - `commonAuth` (CommonAuthPayloadDTO, required): 이메일/비밀번호 및 인증 관련 정보\n - `email` (String, required): 이메일 주소\n - `password` (String, required): 비밀번호(평문)\n - `university` (University enum, required): 대학교 Enum\n - `department` (Department enum, required): 단과대 Enum\n - `major` (Major enum, required): 전공 Enum\n - `commonInfo` (CommonInfoPayloadDTO, required): 사용자 기본 정보\n - `name` (String, required): 업체명\n - `detailAddress` (String, required): 상세 주소\n - `selectedPlace` (SelectedPlacePayload, required): 선택된 장소 정보\n - `placeId` (String, required): 장소 ID\n - `name` (String, required): 장소 이름\n - `address` (String, required): 장소 지번 주소\n - `roadAddress` (String, required): 장소 도로명 주소\n - `latitude` (Double, required): 장소 위도\n - `longitude` (Double, required): 장소 경도\n - `licenseImage` (MultipartFile, required): 사업자등록증 이미지 파일\n\n**Response:**\n - 성공 시 200(OK)과 `SignUpResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (PARTNER)\n - `status` (ActivationStatus): 회원 상태 (ACTIVE)\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 업체명\n - `university` (String): null (Partner는 해당 없음)\n - `department` (String): null (Partner는 해당 없음)\n - `major` (String): null (Partner는 해당 없음)", - "operationId": "signupPartner", - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "request": { - "$ref": "#/components/schemas/PartnerSignUpRequestDTO" - }, - "licenseImage": { - "type": "string", - "format": "binary", - "description": "사업자등록증 이미지 파일" - } - }, - "required": [ - "licenseImage", - "request" - ] - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseSignUpResponseDTO" - } - } - } - } - } - } - }, - "/auth/logout": { - "post": { - "tags": [ - "Auth" - ], - "summary": "로그아웃 API", - "description": "# [v1.0 (2025-09-03)](https://clumsy-seeder-416.notion.site/23a1197c19ed809e9a09fcd741f554c8?source=copy_link)\n- 헤더로 호출합니다.\n- 헤더: `Authorization: Bearer `.\n- 처리: Refresh 무효화(선택), Access 블랙리스트 등록.\n- 성공 시 200(OK).", - "operationId": "logout", - "parameters": [ - { - "name": "Authorization", - "in": "header", - "description": "Access Token. 형식: `Bearer `", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/auth/email-verification/check": { - "post": { - "tags": [ - "Auth" - ], - "summary": "이메일 형식 및 중복가입 확인 API", - "description": "# [v1.0 (2025-09-18)](https://clumsy-seeder-416.notion.site/2551197c19ed802d8f6dd373dd045f3a?source=copy_link)\n- 입력한 이메일이 이미 가입된 사용자가 있는지 확인합니다.\n- 중복된 이메일이 있으면 에러를 반환합니다.\n\n**Request Body:**\n - `email` (String, required): 확인할 이메일 주소\n\n**Response:**\n - 성공 시 200(OK)과 사용 가능 메시지 반환\n - 중복 시 404(NOT_FOUND)와 에러 메시지 반환", - "operationId": "checkEmailAvailability", - "requestBody": { - "description": "이메일 중복 확인 요청", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EmailVerificationCheckRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/auth/commons/login": { - "post": { - "tags": [ - "Auth" - ], - "summary": "공통 로그인 API", - "description": "# [v1.1 (2025-09-13)](https://clumsy-seeder-416.notion.site/2241197c19ed811c961be6a474de0e50)\n- `application/json`로 호출합니다.\n- 바디: `CommonLoginRequestDTO(email, password)`.\n- 처리: 자격 증명 검증 후 Access/Refresh 토큰 발급 및 저장.\n- 성공 시 200(OK)과 토큰(accessToken/refreshToken), 기본 정보 반환.\n\n**Request Body:**\n - `CommonLoginRequestDTO` 객체 (JSON, required): 로그인 정보\n - `email` (String, required): 이메일 주소\n - `password` (String, required): 비밀번호\n\n**Response:**\n - 성공 시 200(OK)과 `LoginResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (PARTNER/ADMIN)\n - `status` (ActivationStatus): 회원 상태\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 업체명/단체명/관리자 이름\n - `university` (String): Admin인 경우 한글명, Partner인 경우 null\n - `department` (String): Admin인 경우 한글명, Partner인 경우 null\n - `major` (String): Admin인 경우 한글명, Partner인 경우 null", - "operationId": "loginCommon", - "requestBody": { - "description": "공통 로그인 요청 (파트너/관리자)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CommonLoginRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseLoginResponseDTO" - } - } - } - } - } - } - }, - "/auth/admins/signup": { - "post": { - "tags": [ - "Auth" - ], - "summary": "관리자 회원가입 API", - "description": "# [v1.2 (2025-09-13)](https://clumsy-seeder-416.notion.site/2501197c19ed80cdb98bc2b4d5042b48)\n- `multipart/form-data`로 호출합니다.\n- 파트: `request`(JSON, AdminSignUpRequestDTO) + `signImage`(파일, 신분증).\n- 처리: users + common_auth 생성, 이메일 중복/비밀번호 규칙 검증.\n- 성공 시 200(OK)과 생성된 memberId, JWT 토큰, 기본 정보 반환.\n\n**Request Parts:**\n - `request` (JSON, required): `AdminSignUpRequestDTO` 객체\n - `phoneNumber` (String, required): 휴대폰 번호\n - `marketingAgree` (Boolean, required): 마케팅 수신 동의\n - `locationAgree` (Boolean, required): 위치 정보 수집 동의\n - `commonAuth` (CommonAuthPayloadDTO, required): 이메일/비밀번호 및 인증 관련 정보\n - `email` (String, required): 이메일 주소\n - `password` (String, required): 비밀번호(평문)\n - `university` (University enum, required): 대학교 Enum\n - `department` (Department enum, required): 단과대 Enum\n - `major` (Major enum, required): 전공 Enum\n - `commonInfo` (CommonInfoPayloadDTO, required): 사용자 기본 정보\n - `name` (String, required): 단체명/관리자 이름\n - `detailAddress` (String, required): 상세 주소\n - `selectedPlace` (SelectedPlacePayload, required): 선택된 장소 정보\n - `placeId` (String, required): 장소 ID\n - `name` (String, required): 장소 이름\n - `address` (String, required): 장소 지번 주소\n - `roadAddress` (String, required): 장소 도로명 주소\n - `latitude` (Double, required): 장소 위도\n - `longitude` (Double, required): 장소 경도\n - `signImage` (MultipartFile, required): 인감 이미지 파일\n\n**Response:**\n - 성공 시 200(OK)과 `SignUpResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (ADMIN)\n - `status` (ActivationStatus): 회원 상태 (ACTIVE)\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 단체명/관리자 이름\n - `university` (String): 대학교 (한글명)\n - `department` (String): 단과대 (한글명)\n - `major` (String): 전공/학과 (한글명)", - "operationId": "signupAdmin", - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "request": { - "$ref": "#/components/schemas/AdminSignUpRequestDTO" - }, - "signImage": { - "type": "string", - "format": "binary", - "description": "인감 이미지 파일 (Multipart Part)" - } - }, - "required": [ - "request", - "signImage" - ] - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseSignUpResponseDTO" - } - } - } - } - } - } - }, - "/app-reviews": { - "post": { - "tags": [ - "App Review" - ], - "summary": "앱 리뷰 작성 API", - "description": "# [v1.0 (2026-02-09)](https://clumsy-seeder-416.notion.site/3021197c19ed80cf9ce3e7b8d7401fad)\n- `application/json`로 호출합니다.\n- 바디: `AppReviewRequestDTO(rate, content)`.\n- 처리: 자격 증명 검증 후 앱 리뷰 생성 및 저장.\n- 성공 시 200(OK) 반환.\n\n**Request Body:**\n - `rate` (Integer, required): 별점 1~5\n - `content` (String, required): 후기 내용\n\n**Response:**\n - 성공 시 200(OK)과 성공 메시지 반환", - "operationId": "createAppReview", - "requestBody": { - "description": "앱 리뷰 작성 요청", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AppReviewRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/partnership/{partnershipId}/status": { - "patch": { - "tags": [ - "Partnership" - ], - "summary": "제휴 상태 업데이트 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/SUSPEND-ACTIVE-INACTIVE-2371197c19ed805ab509f552817e823a)\n- 제휴 상태를 변경합니다.\n- 적용할 상태 입력 (ACTIVE/SUSPEND/INACTIVE).\n\n**Parameters:**\n - `partnershipId` (Long, required): 상태를 적용할 제안서 ID\n\n**Request Body:**\n - `UpdateRequest` 객체 (JSON, required)\n - `status` (String): 제안서에 적용할 상태\n\n**Response:**\n - 성공 시 200(OK)과 `UpdateResponse` 객체 반환.\n - `partnershipId` (Long): 생성된 제안서 ID\n - `prevStatus` (String): 제안서의 이전 상태\n - `newStatus` (String): 제안서의 이전 상태\n - `changedAt` (LocalDateTime): 상태 변경 시간\n", - "operationId": "updatePartnershipStatus", - "parameters": [ - { - "name": "partnershipId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PartnershipStatusUpdateRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePartnershipStatusUpdateResponseDTO" - } - } - } - } - } - } - }, - "/partnership/proposal": { - "patch": { - "tags": [ - "Partnership" - ], - "summary": "제휴 제안서 내용 수정 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2371197c19ed80aa8468d2377ef8eac2)\n- 제안서 초안 또는 이미 작성된 제안서의 내용을 수정합니다.\n- options의 optionType을 SERVICE/DISCOUNT 중 하나로 설정\n- options의 criterionType을 PRICE/HEADCOUNT 중 하나로 설정\n- 이외의 제휴 유형일 경우 anotherType을 true로 설정\n\n**Request Body:**\n - `WritePartnershipRequest` 객체 (JSON, required): 수정 내용\n - `paperId` (String): 이메일 주소\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `goods` (JSON): 서비스 제공 항목\n - `goodsName` (String): 서비스 제공 항목명\n\n**Response:**\n - 성공 시 200(OK)과 `WritePartnershipResponse` 객체 반환\n - `partnershipId` (Long): 제안서 ID\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `storeName` (String): 가게 이름\n - `adminName` (String): 관리자 이름\n - `isActivated` (ActivationStatus): 제안서 활성화 여부\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", - "operationId": "updatePartnership", - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/WritePartnershipRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseWritePartnershipResponseDTO" - } - } - } - } - } - } - }, - "/inquiries/{inquiryId}/answer": { - "patch": { - "tags": [ - "Inquiry" - ], - "summary": "운영자 답변 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed8064808fcca568b8912a?source=copy_link)\n- 문의에 답변을 저장하고 상태를 ANSWERED로 변경합니다.\n\n**Path Variable:**\n- `inquiryId` (Long, required): 문의 ID\n\n**Request Body:**\n- `answer` (String, required): 답변 내용\n\n**Response:**\n- 성공 시 200(OK)과 성공 메시지 반환\n- 400(BAD_REQUEST): 빈 답변 내용\n- 403(FORBIDDEN): 운영자 권한 없음\n- 404(NOT_FOUND): 존재하지 않는 문의 ID\n- 409(CONFLICT): 이미 답변된 문의", - "operationId": "answer", - "parameters": [ - { - "name": "inquiryId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InquiryAnswerRequestDTO" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseString" - } - } - } - } - } - } - }, - "/chat/rooms/{roomId}/read": { - "patch": { - "tags": [ - "Chatting" - ], - "summary": "메시지 읽음 처리 API", - "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed800eab45c35073761c97?v=2241197c19ed8134b64f000cc26c5d31&p=2241197c19ed81ffa771cb18ab157b54&pm=s)\n- 메시지를 읽음처리합니다.\n\n**Path Variable:**\n- roomId (Long, required): 채팅방 ID\n", - "operationId": "readMessage", - "parameters": [ - { - "name": "roomId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseReadMessageResponseDTO" - } - } - } - } - } - } - }, - "/auth/withdraw": { - "patch": { - "tags": [ - "Auth" - ], - "summary": "회원 탈퇴 API", - "description": "# [v1.0 (2025-09-13)](https://clumsy-seeder-416.notion.site/2501197c19ed800a844bdafa2e2e8d2e?source=copy_link)\n- 현재 로그인한 사용자의 회원 탈퇴를 처리합니다.\n- 소프트 삭제 방식으로, 한 달 후 완전히 삭제됩니다.\n- 탈퇴 즉시 모든 토큰이 무효화됩니다.\n\n**Headers:**\n - `Authorization` (String, required): Bearer 토큰 형식의 액세스 토큰\n\n**Response:**\n - 성공 시 200(OK)과 성공 메시지 반환\n - 탈퇴 후 재로그인 가능", - "operationId": "withdrawMember", - "parameters": [ - { - "name": "Authorization", - "in": "header", - "description": "Access Token. 형식: `Bearer `", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/temporary-qr/mydata": { - "get": { - "tags": [ - "Temp QR" - ], - "summary": "내 QR 적립 데이터 조회 API", - "description": "# # [v1.0 (2026-02-15)](https://clumsy-seeder-416.notion.site/QR-3081197c19ed805e9f6bd012dafe6f01?source=copy_link)\n- 로그인한 사용자의 임시 QR 적립 데이터를 조회합니다.\n- 인증된 사용자의 토큰을 통해 자동으로 데이터를 가져옵니다.\n\n**Request:**\n - 별도의 파라미터 없음 (토큰 기반 인증)\n\n**Response:**\n - `adminName` (String): 학생회(관리자) 이름- 만약 앱 리뷰인 경우 \"\" 와 같이 들어가게 됨\n - `sort` (Enum): 적립 방식 (REVIEW/SUGGEST)\n - `createdAt` (String): 적립 일시\n\n**Response Example:**\n```json\n[\n {\n \"adminName\": \"총학생회\",\n \"sort\": \"SUGGEST\"\n \"createdAt\": \"2026-02-03\"\n },\n {\n \"adminName\": \"\",\n \"sort\": \"REVIEW\"\n \"createdAt\": \"2026-02-03\"\n }\n]\n```\n\n**Status:**\n - 성공 시 200(OK)\n", - "operationId": "getMyStampData", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseListTemporaryQrResponseDTO" - } - } - } - } - } - } - }, - "/suggestion/list": { - "get": { - "tags": [ - "Suggestion" - ], - "summary": "제휴 건의 조회 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-24c1197c19ed8083bf8be4b6a6a43f18)\n- 현재 로그인한 관리자가 받은 모든 제휴 건의를 조회합니다.\n- 제휴 건의는 작성일 기준 최신순으로 조회.\n- enrollmentStatus로 재학 상태 표시(ENROLLED, LEAVE, GRADUATED)\n- 성공 시 200(OK)과 Suggestion 객체 반환.\n\n**Response:**\n - `suggestionId` (Long): 건의 ID\n - `createdAt` (LocalDateTime): 건의 작성일\n - `storeName` (String): 희망 가게 이름\n - `content` (String): 건의 내용\n - `studentMajor` (Long): 건의자의 학부/학과\n - `enrollmentStatus` (EnrollmentStatus): 재학 상태\n", - "operationId": "getSuggestions", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseListGetSuggestionResponseDTO" - } - } - } - } - } - } - }, - "/suggestion/admin": { - "get": { - "tags": [ - "Suggestion" - ], - "summary": "제휴 건의대상 조회 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-2621197c19ed808c9627fcb7f58f4538)\n- 현재 로그인한 학생이 건의할 수 있는 관리자를 조회합니다.\n- 성공 시 200(OK)과 SuggestionAdmins 객체 반환.\n\n**Response:**\n - `adminId` (Long): 총학생회 ID\n - `adminName` (String): 총학생회 이름\n - `departId` (Long): 단과대학 학생회 ID\n - `departName` (String): 단과대학 학생회 이름\n - `majorId` (Long): 학부/학과 학생회 ID\n - `majorName` (String): 학부/학과 학생회 이름\n", - "operationId": "getSuggestionAdmins", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseGetSuggestionAdminsDTO" - } - } - } - } - } - } - }, - "/students/usage": { - "get": { - "tags": [ - "Student" - ], - "summary": "리뷰되지 않은 제휴 사용내역 조회 API", - "description": "# [v1.0 (2025-09-10)](https://www.notion.so/_-24c1197c19ed809a9d81e8f928e8355f?source=copy_link)\n- `multipart/form-data`로 호출합니다.\n\n**Request:**\n - page : (Int, required) 이상의 정수 \n - size : (Int, required) 기본 값 10 \n - sort : (String, required) createdAt/desc 문자열로 입력\n\n**Response:**\n - 성공 시 리뷰 되지 않은 partnership Usage 내역 반환 \n - StudentResponseTO.UsageDetailDTO 객체 반환 \n", - "operationId": "getUnreviewedUsage", - "parameters": [ - { - "name": "pageable", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/Pageable" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePageUsageDetail" - } - } - } - } - } - } - }, - "/students/usable": { - "get": { - "tags": [ - "Student" - ], - "summary": "사용자의 이용 가능한 제휴 조회 API", - "description": "# [v1.0 (2025-10-30)](https://clumsy-seeder-416.notion.site/API-29c1197c19ed8030b1f5e2a744416651?source=copy_link)\n- 현재 로그인한 사용자가 이용 가능한 제휴 목록을 조회합니다.\n- 활성 상태인 제휴만 반환합니다.\n\n**Request Parameters:**\n- `all` (Boolean, optional): 전체 조회 여부 - 기본값: false\n - true: 모든 이용 가능한 제휴 조회\n - false: 최대 2개만 조회\n\n**Response:**\n- 성공 시 200(OK)와 이용 가능한 제휴 목록 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 404(NOT_FOUND): 사용자 정보를 찾을 수 없음", - "operationId": "getUsablePartnership", - "parameters": [ - { - "name": "all", - "in": "query", - "required": false, - "schema": { - "type": "boolean", - "default": false - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseListUsablePartnershipDTO" - } - } - } - } - } - } - }, - "/students/partnerships/{year}/{month}": { - "get": { - "tags": [ - "Student" - ], - "summary": "월별 제휴 사용내역 조회 API", - "description": "# [v1.0 (2025-09-09)](https://www.notion.so/_-2241197c19ed8134bd49d8841e841634?source=copy_link)\n- `multipart/form-data`로 호출합니다.\n\n**Request Parts:**\n - `year` (Integer, required): 년도\n - `month` (Long, required): 월\n\n**Response:**\n - 성공 시 partnership Usage 내역 반환 \n - 해당 storeId, storeName 반환 - 해당 월에 사용한 제휴 수 반환", - "operationId": "getMyPartnership", - "parameters": [ - { - "name": "year", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "month", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseMyPartnership" - } - } - } - } - } - } - }, - "/store/{storeId}/papers": { - "get": { - "tags": [ - "Store" - ], - "summary": "제휴 컨텐츠 조회 API", - "description": "# [v1.0 (2026-02-14)](https://clumsy-seeder-416.notion.site/2361197c19ed8019b8b8cb054cd3135b?source=copy_link)\n- 유저가 속한 단과대 및 학부의 `admin_id`와 요청한 `store_id`를 매칭하여 적용 가능한 제휴 컨텐츠를 조회합니다.\n- QR 코드 스캔 후 유저에게 실제로 보여줄 혜택(Paper) 목록을 가져올 때 사용됩니다.\n\n**Path Variable:**\n - `storeId` (Long, required): QR에서 추출한 제휴 매장 ID\n\n**Query Parameters:**\n - (없음) - 유저 정보는 토큰(@AuthenticationPrincipal)을 통해 식별합니다.\n\n**Response (PaperResponseDTO):**\n - `storeId` (Long): 매장 고유 ID\n - `storeName` (String): 매장 이름\n - `partnershipContents` (List): 제휴 컨텐츠 상세 목록\n - `adminId` (Long): 혜택 제공자 ID\n - `adminName` (String): 혜택 제공자 이름 (예: OO대학 학생회)\n - `paperContent` (String): 제휴 혜택 상세 설명\n - `contentId` (Long): 컨텐츠 고유 ID\n - `goods` (List): 제공되는 상품/서비스 리스트\n - `people` (Integer): 사용 가능 인원\n - `cost` (Long): 유저 부담 금액 (0이면 무료)\n\n**Error Cases:**\n - 성공: 200 OK, `isSuccess=true`, `result=PaperResponseDTO` (제휴 컨텐츠 상세 정보)\n - 실패: \n - 404 NOT_FOUND: 해당 매장을 찾을 수 없거나 유효한 제휴 컨텐츠가 없는 경우\n - 403 FORBIDDEN: 유저 권한이 없거나 인증에 실패한 경우", - "operationId": "getStorePaperContent", - "parameters": [ - { - "name": "storeId", - "in": "path", - "description": "QR에서 추출한 storeId를 입력해주세요", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePaperResponseDTO" - } - } - } - } - } - } - }, - "/store/stamp-ranking": { - "get": { - "tags": [ - "Store" - ], - "summary": "스탬프 기준 인기 매장 랭킹 조회 API", - "description": "# [v1.0 (2026-02-09)](https://clumsy-seeder-416.notion.site/API-3001197c19ed806a99a8fa3e795aba8e?source=copy_link)\n- 하루 동안 스탬프가 많이 적립된 매장 순위를 조회합니다.\n- 최대 10개까지 반환\n- 로그인 필요 없음\n\n**Response:**\n - `rankings` (List): 매장 랭킹 목록\n - `storeId` (Long): 매장 ID\n - `storeName` (String): 매장 이름\n - `stampCount` (Long): 스탬프 적립 횟수", - "operationId": "getStampRanking", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseStampRankingListDTO" - } - } - } - } - } - } - }, - "/store/ranking": { - "get": { - "tags": [ - "Store" - ], - "summary": "내 가게 순위 조회 API", - "description": "# [v1.0 (2025-12-23)](https://www.notion.so/내-가게-순위-API_문서)\n- partnerId로 접근 가능합니다.\n- 로그인된 파트너만 조회 가능\n\n**Response:**\n - `rank` (Long): 그 주 순위 (1부터)\n - `usageCount` (Long): 그 주 사용 건수", - "operationId": "getWeeklyRank", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseWeeklyRankResponseDTO" - } - } - } - } - } - } - }, - "/store/ranking/weekly": { - "get": { - "tags": [ - "Store" - ], - "summary": "내 가게 순위 6주치 조회 API", - "description": "partnerId로 접근해주세요", - "operationId": "getWeeklyRankByPartnerId", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseListWeeklyRankResponseDTO" - } - } - } - } - } - } - }, - "/store/best": { - "get": { - "tags": [ - "Store" - ], - "summary": "오늘 인기 매장 조회 API", - "description": "# [v1.0 (2025-12-23)](https://clumsy-seeder-416.notion.site/Today-22b1197c19ed80aebfc3e6b337d02ece?source=copy_link)\n- 오늘 기준 인기 매장 목록을 조회합니다.\n- 로그인 필요 없음\n\n**Response:**\n - `bestStores` (List): 오늘 가장 인기 있는 매장 이름 목록", - "operationId": "getTodayBestStore", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseTodayBestResponseDTO" - } - } - } - } - } - } - }, - "/reviews/student": { - "get": { - "tags": [ - "Review" - ], - "summary": "내가 쓴 리뷰 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/22b1197c19ed8057b158c88f6153d073)\n- 로그인한 학생 사용자가 작성한 리뷰 목록을 페이징하여 조회합니다.", - "operationId": "checkStudent", - "parameters": [ - { - "name": "pageable", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/Pageable" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePageCheckReviewResponseDTO" - } - } - } - } - } - } - }, - "/reviews/store/{storeId}": { - "get": { - "tags": [ - "Review" - ], - "summary": "가게 리뷰 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2681197c19ed80038db3f7dd357623ff)\n- 특정 storeId를 기반으로 해당 가게의 모든 리뷰를 조회합니다.", - "operationId": "checkStoreReview", - "parameters": [ - { - "name": "pageable", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/Pageable" - } - }, - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePageCheckReviewResponseDTO" - } - } - } - } - } - } - }, - "/reviews/partner": { - "get": { - "tags": [ - "Review" - ], - "summary": "내 가게 리뷰 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-2241197c19ed8130b89ad5a77f3e8b2c)\n- 로그인한 파트너 계정의 가게에 달린 리뷰 목록을 페이징하여 조회합니다.", - "operationId": "checkPartnerReview", - "parameters": [ - { - "name": "pageable", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/Pageable" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePageCheckReviewResponseDTO" - } - } - } - } - } - } - }, - "/reviews/average": { - "get": { - "tags": [ - "Review" - ], - "summary": "내 가게 리뷰 평균 조회 API (파트너)", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/API-2681197c19ed80df9f2ac100812c7f44)\n- 파트너 로그인 시 본인 가게의 평균 평점을 조회합니다.", - "operationId": "getMyStoreAverage", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseStandardScoreResponseDTO" - } - } - } - } - } - } - }, - "/reviews/average/{storeId}": { - "get": { - "tags": [ - "Review" - ], - "summary": "가게 리뷰 평균 조회 API (ID 기반)", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2ef1197c19ed80a5a08fd4d2aa031e5f)\n- 특정 storeId 기반으로 해당 가게의 리뷰 평점을 조회합니다.", - "operationId": "getStandardScore", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseStandardScoreResponseDTO" - } - } - } - } - } - } - }, - "/partnership/{partnershipId}": { - "get": { - "tags": [ - "Partnership" - ], - "summary": "제휴 상세조회 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2371197c19ed80cdac8beb2ffddb2f61)\n- 제휴 제안서의 내용을 조회합니다.\n- 적용할 상태 입력 (ACTIVE/SUSPEND/INACTIVE).\n\n**Parameters:**\n - `partnershipId` (Long, required): 내용을 조회할 제안서 ID\n\n**Response:**\n - 성공 시 200(OK)과 `GetPartnershipDetailResponse` 객체 반환.\n - `partnershipId` (Long): 제안서 ID\n - `updatedAt` (LocalDateTime): 업데이트된 시간\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", - "operationId": "getPartnership", - "parameters": [ - { - "name": "partnershipId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePartnershipDetailResponseDTO" - } - } - } - } - } - } - }, - "/partnership/suspended": { - "get": { - "tags": [ - "Partnership" - ], - "summary": "대기 중인 제휴 계약서 조회 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-24f1197c19ed802784fddadbbd3ea2c6)\n- 현재 로그인한 관리자와 제휴 중인 제안서 중 SUSPEND 상태인 제안서를 모두 조회합니다.\n\n**Response:**\n - 성공 시 200(OK)과 `SuspendedPaper` 객체 반환.\n - `paperId` (Long): 제안서 ID\n - `partnerName` (String): 제휴업체 이름\n - `createdAt` (LocalDateTime): 제휴 생성 일자\n", - "operationId": "suspendPartnership", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseListSuspendedPaperResponseDTO" - } - } - } - } - } - } - }, - "/partnership/partner": { - "get": { - "tags": [ - "Partnership" - ], - "summary": "제휴 중인 관리자 조회 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-24f1197c19ed802784fddadbbd3ea2c6)\n- 현재 로그인한 제휴업체와 제휴 중인 관리자를 조회합니다.\n- 전체를 조회하려면 all을 true로, 가장 최근 두 건을 조회하려면 all을 false로 설정.\n\n**Parameters:**\n - `all` (boolean, required): 조회 옵션\n\n**Response:**\n - 성공 시 200(OK)과 `WritePartnershipResponse` 객체 반환.\n - `partnershipId` (Long): 제안서 ID\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `storeName` (String): 가게 이름\n - `adminName` (String): 관리자 이름\n - `isActivated` (ActivationStatus): 제안서 활성화 여부\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", - "operationId": "listForPartner", - "parameters": [ - { - "name": "pageable", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/Pageable" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePageWritePartnershipResponseDTO" - } - } - } - } - } - } - }, - "/partnership/check/partner/{adminId}": { - "get": { - "tags": [ - "Partnership" - ], - "summary": "채팅방 내 제휴 확인 API(제휴업체용)", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed8078af77d65bfcc09087)\n- 현재 로그인한 제휴업체와 파라미터로 받은 adminId를 가진 관리자 간에 제휴를 조회합니다.\n- 비활성화 되지 않은 가장 최근 제휴 1건 조회.\n\n**Parameters:**\n - `adminId` (Long, required): 관리자 ID\n\n**Response:**\n - 성공 시 200(OK)과 `PartnerPartnershipWithAdminResponse` 객체 반환.\n - `paperId` (Long): 제안서 ID\n - `isPartnered` (boolean): 제휴 여부\n - `status` (String): 제휴 상태\n - `adminId` (Long): 관리자 ID\n - `adminName` (String): 관리자 이름\n - `adminAddress` (String): 관리자 주소\n", - "operationId": "checkPartnerPartnership", - "parameters": [ - { - "name": "adminId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePartnerPartnershipCheckResponseDTO" - } - } - } - } - } - } - }, - "/partnership/check/admin/{partnerId}": { - "get": { - "tags": [ - "Partnership" - ], - "summary": "채팅방 내 제휴 확인 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-31f1197c19ed8017bceced3b3d65c0d7?source=copy_link)\n- 현재 로그인한 관리자와 파라미터로 받은 partnerId를 가진 제휴업체 간에 제휴를 조회합니다.\n- 비활성화 되지 않은 가장 최근 제휴 1건 조회.\n\n**Parameters:**\n - `partnerId` (Long, required): 제휴업체 ID\n\n**Response:**\n - 성공 시 200(OK)과 `AdminPartnershipWithPartnerResponse` 객체 반환.\n - `paperId` (Long): 제안서 ID\n - `isPartnered` (boolean): 제휴 여부\n - `status` (String): 제휴 상태\n - `partnerId` (Long): 제휴업체 ID\n - `partnerName` (String): 제휴업체 이름\n - `partnerAddress` (String): 제휴업체 주소\n", - "operationId": "checkAdminPartnership", - "parameters": [ - { - "name": "partnerId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseAdminPartnershipCheckResponseDTO" - } - } - } - } - } - } - }, - "/partnership/admin": { - "get": { - "tags": [ - "Partnership" - ], - "summary": "제휴 중인 가게 조회 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-2241197c19ed81b1b9adf724adc4600c)\n- 현재 로그인한 관리자와 제휴 중인 가게를 조회합니다.\n- 전체를 조회하려면 all을 true로, 가장 최근 두 건을 조회하려면 all을 false로 설정.\n\n**Parameters:**\n - `all` (boolean, required): 조회 옵션\n\n**Response:**\n - 성공 시 200(OK)과 `WritePartnershipResponse` 객체 반환.\n - `partnershipId` (Long): 제안서 ID\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `storeName` (String): 가게 이름\n - `adminName` (String): 관리자 이름\n - `isActivated` (ActivationStatus): 제안서 활성화 여부\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", - "operationId": "listForAdmin", - "parameters": [ - { - "name": "pageable", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/Pageable" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePageWritePartnershipResponseDTO" - } - } - } - } - } - } - }, - "/partner/admin-recommend": { - "get": { - "tags": [ - "Partner" - ], - "summary": "관리자 추천 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed80368a9edf1f6e92ea38)\n- 현재 로그인 한 제휴업체와 제휴하지 않은 관리자 중 최대 두 곳을 랜덤으로 조회합니다.\n\n**Response:**\n - 성공 시 200(OK)과 `RandomAdminResponse` 객체(최대 두 개) 반환\n - `adminId` (Long): 관리자 ID\n - `adminAddress` (String): 관리자 주소\n - `adminDetailAddress` (String): 관리자 상세주소\n - `adminName` (String): 관리자 상호명\n - `adminUrl` (String): 관리자 카카오맵 URL\n - `adminPhone` (String): 관리자 전화번호\n", - "operationId": "randomAdminRecommend", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponsePartnerResponseDTO" - } - } - } - } - } - } - }, - "/notifications": { - "get": { - "tags": [ - "Notification" - ], - "summary": "알림 목록 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2491197c19ed8091b349ef0ef4bb0f60?source=copy_link)\n- 본인의 알림 목록을 상태별로 조회합니다.\n\n**Request Parameters:**\n- `status` (String, optional): 알림 상태 (all, unread) - 기본값: all\n- `page` (Integer, optional): 페이지 번호 (1 이상) - 기본값: 1\n- `size` (Integer, optional): 페이지 크기 - 기본값: 20\n\n**Response:**\n- 성공 시 200(OK)과 알림 목록 반환\n- 400(BAD_REQUEST): 잘못된 상태 값 또는 페이지 번호\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", - "operationId": "list_1", - "parameters": [ - { - "name": "status", - "in": "query", - "required": false, - "schema": { - "type": "string", - "default": "all" - } - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseMapStringObject" - } - } - } - } - } - } - }, - "/notifications/unread-exists": { - "get": { - "tags": [ - "Notification" - ], - "summary": "읽지 않은 알림 존재 여부 조회 API", - "description": "# [v1.0 (2025-09-02)](https://clumsy-seeder-416.notion.site/2691197c19ed809a81fec6eb3282ec3a?source=copy_link)\n- 현재 로그인 사용자의 읽지 않은 알림 존재 여부를 반환합니다.\n- 알림 배지 표시 여부를 결정하는 데 사용됩니다.\n\n**Response:**\n- 성공 시 200(OK)와 존재 여부 반환\n- true: 읽지 않은 알림 있음, false: 모든 알림 읽음\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", - "operationId": "unreadExists", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseBoolean" - } - } - } - } - } - } - }, - "/notifications/settings": { - "get": { - "tags": [ - "Notification" - ], - "summary": "알림 현재 설정 조회 API", - "description": "# [v1.0 (2025-09-02)](https://clumsy-seeder-416.notion.site/2691197c19ed80de9b92d96db3608cdf?source=copy_link)\n- 현재 로그인 사용자의 알림 설정 상태를 반환합니다.\n- 모든 알림 유형에 대한 ON/OFF 상태를 확인할 수 있습니다.\n\n**Response:**\n- 성공 시 200(OK)와 알림 설정 상태 반환\n- 각 알림 유형별 true/false 값 포함\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", - "operationId": "getSettings", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseNotificationSettingsResponseDTO" - } - } - } - } - } - } - }, - "/map/search": { - "get": { - "tags": [ - "Map" - ], - "summary": "검색어 기반 장소 조회 API", - "description": "# [v1.3 (2025-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed8017adf1f3d711bab3d4)\n- 로그인한 유저의 역할과 검색어에 따라 Map 객체를 반환합니다.\n- 검색어(searchKeyword) 입력.\n- 성공 시 200(OK)과 Map 객체 반환.\n\n**Request Parts:**\n - `searchKeyword` (String, required): 검색어\n\n**Response:**\n - `User`: 가게 조회\n - `storeId` (Long): 가게 ID\n - `name` (String): 가게 이름\n - `address` (String): 가게 주소\n - `rate` (Integer): 가게 별점\n - `hasPartner` (boolean): 제휴업체인지 여부\n - `latitude` (Double): 가게 위치 위도\n - `longitude` (Double): 가게 위치 경도\n - `profileUrl` (String): 가게 카카오맵 URL\n - `phoneNumber` (String): 가게 전화번호\n - `partnerships` (Array): 제휴 정보 목록\n - `adminId` (Long): 관리자 ID\n - `adminName` (String): 관리자 이름\n - `benefits` (Array): 혜택 목록\n - `Admin`: 제휴업체 조회\n - `partnerId` (Long): 제휴업체 ID\n - `name` (String): 제휴업체 이름\n - `address` (String): 제휴업체 주소\n - `isPartnered` (boolean): 관리자와 제휴 여부\n - `partnershipId` (Long): 제휴 ID\n - `partnershipStartDate` (LocalDate): 제휴 시작일\n - `partnershipEndDate` (LocalDate): 제휴 마감일\n - `latitude` (Double): 제휴업체 위도\n - `longitude` (Double): 제휴업체 경도\n - `profileUrl` (String): 제휴업체 카카오맵 Url\n - `phoneNumber` (String): 제휴업체 전화번호\n - `Partner`: 관리자 조회\n - `adminId` (Long): 관리자 ID\n - `name` (String): 관리자 이름\n - `address` (String): 관리자 주소\n - `isPartnered` (boolean): 제휴업체와 제휴 여부\n - `partnershipId` (Long): 제휴 ID\n - `partnershipStartDate` (LocalDate): 제휴 시작일\n - `partnershipEndDate` (LocalDate): 제휴 마감일\n - `latitude` (Double): 관리자 위도\n - `longitude` (Double): 관리자 경도\n - `profileUrl` (String): 관리자 카카오맵 Url\n - `phoneNumber` (String): 관리자 전화번호\n", - "operationId": "getLocationsByKeyword", - "parameters": [ - { - "name": "searchKeyword", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseObject" - } - } - } - } - } - } - }, - "/map/place": { - "get": { - "tags": [ - "Map" - ], - "summary": "카카오맵 기반 장소 검색 API", - "description": "# [v1.3 (2025-01-04)](https://clumsy-seeder-416.notion.site/25d1197c19ed807eb7a7c5ede2e75040)\n- 검색어에 따라 Map 객체를 반환합니다.\n- 검색어(searchKeyword) 입력.\n- limit을 통해 Map 객체 수 제한.\n- 성공 시 200(OK)과 Map 객체 반환.\n\n**Request Parts:**\n - `searchKeyword` (String, required): 검색어\n - `limit` (Integer): 결과 객체 수\n\n**Response:**\n - `placeId` (String): kakao place ID\n - `name` (String): kakao place 이름\n - `category` (String): kakao 카테고리 또는 그룹 이름\n - `address` (String): 지번 주소\n - `roadAddress` (String): 도로명 주소\n - `phone` (String): 장소 전화번호\n - `placeUrl` (String): kakao place 상세 URL\n - `latitude` (Double): 장소 위도\n - `longitude` (Double): 장소 경도\n - `distance` (Integer): 장소의 m 좌표 (좌표바이어스/카테고리 검색 시 제공)\n", - "operationId": "search", - "parameters": [ - { - "name": "searchKeyword", - "in": "query", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "limit", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseListPlaceSuggestionDTO" - } - } - } - } - } - } - }, - "/map/nearby": { - "get": { - "tags": [ - "Map" - ], - "summary": "현재 위치 기반 주변 장소 조회 API", - "description": "# [v1.3 (2025-01-04)](https://clumsy-seeder-416.notion.site/2441197c19ed80bcb55fcad675dd9837?source=copy_link)\n- 로그인한 유저의 역할에 따라 Map 객체를 반환합니다.\n- 경도, 위도 순서로 입력한 Viewport 객체 입력.\n- 성공 시 200(OK)과 Map 객체 반환.\n\n**Request Body:**\n - `viewport` 객체 (JSON, required): 공간인덱싱을 위한 경도, 위도 객체\n - `lng1` (double): 좌 상단 경도\n - `lat1` (double): 좌 상단 위도\n - `lng2` (double): 우 상단 경도\n - `lat2` (double): 우 상단 위도\n - `lng3` (double): 우 하단 경도\n - `lat3` (double): 우 하단 위도\n - `lng4` (double): 좌 하단 경도\n - `lat4` (double): 좌 하단 위도\n\n**Response:**\n - `User`: 가게 조회\n - `storeId` (Long): 가게 ID\n - `name` (String): 가게 이름\n - `address` (String): 가게 주소\n - `rate` (Integer): 가게 별점\n - `hasPartner` (boolean): 제휴업체인지 여부\n - `latitude` (Double): 가게 위치 위도\n - `longitude` (Double): 가게 위치 경도\n - `profileUrl` (String): 가게 카카오맵 URL\n - `phoneNumber` (String): 가게 전화번호\n - `partnerships` (Array): 제휴 정보 목록\n - `adminId` (Long): 관리자 ID\n - `adminName` (String): 관리자 이름\n - `benefits` (Array): 혜택 목록\n - `Admin`: 제휴업체 조회\n - `partnerId` (Long): 제휴업체 ID\n - `name` (String): 제휴업체 이름\n - `address` (String): 제휴업체 주소\n - `isPartnered` (boolean): 관리자와 제휴 여부\n - `partnershipId` (Long): 제휴 ID\n - `partnershipStartDate` (LocalDate): 제휴 시작일\n - `partnershipEndDate` (LocalDate): 제휴 마감일\n - `latitude` (Double): 제휴업체 위도\n - `longitude` (Double): 제휴업체 경도\n - `profileUrl` (String): 제휴업체 카카오맵 Url\n - `phoneNumber` (String): 제휴업체 전화번호\n - `Partner`: 관리자 조회\n - `adminId` (Long): 관리자 ID\n - `name` (String): 관리자 이름\n - `address` (String): 관리자 주소\n - `isPartnered` (boolean): 제휴업체와 제휴 여부\n - `partnershipId` (Long): 제휴 ID\n - `partnershipStartDate` (LocalDate): 제휴 시작일\n - `partnershipEndDate` (LocalDate): 제휴 마감일\n - `latitude` (Double): 관리자 위도\n - `longitude` (Double): 관리자 경도\n - `profileUrl` (String): 관리자 카카오맵 Url\n - `phoneNumber` (String): 관리자 전화번호\n", - "operationId": "getLocations", - "parameters": [ - { - "name": "viewport", - "in": "query", - "required": true, - "schema": { - "$ref": "#/components/schemas/MapRequestDTO" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseObject" - } - } - } - } - } - } - }, - "/inquiries/{inquiryId}": { - "get": { - "tags": [ - "Inquiry" - ], - "summary": "문의 내역 단건 상세 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed800f8a1fffc5a101f3c0?source=copy_link)\n- 본인의 문의 내역 중 1건의 문의를 상세 조회합니다.\n\n**Path Variable:**\n- `inquiryId` (Long, required): 문의 ID\n\n**Response:**\n- 성공 시 200(OK)과 문의 상세 정보 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 403(FORBIDDEN): 다른 사용자의 문의 접근 시도\n- 404(NOT_FOUND): 존재하지 않는 문의 ID", - "operationId": "get", - "parameters": [ - { - "name": "inquiryId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseInquiryResponseDTO" - } - } - } - } - } - } - }, - "/chat/rooms/{roomId}/messages": { - "get": { - "tags": [ - "Chatting" - ], - "summary": "채팅방 상세 조회 API", - "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed800eab45c35073761c97?v=2241197c19ed8134b64f000cc26c5d31&p=2241197c19ed81399395fd66f73730af&pm=s)\n- 채팅방을 클릭했을 때 메시지를 조회합니다.\n\n**Path Variable:**\n- roomId (Long, required): 채팅방 ID\n", - "operationId": "getChatHistory", - "parameters": [ - { - "name": "roomId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseChatHistoryResponseDTO" - } - } - } - } - } - } - }, - "/chat/check/block/{opponentId}": { - "get": { - "tags": [ - "Chatting" - ], - "summary": "상대방 차단 여부 확인 API", - "description": "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed80769521eab9660ac53f)\n- 상대방을 차단했는지 검사합니다.\n\n**Path Variable:**\n- opponentId (Long, required): 상대방 ID\n", - "operationId": "checkBlock", - "parameters": [ - { - "name": "opponentId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCheckBlockMemberDTO" - } - } - } - } - } - } - }, - "/chat/block-list": { - "get": { - "tags": [ - "Chatting" - ], - "summary": "차단한 대상 조회 API", - "description": "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed8000b047d9857bcbbb2f)\n- 차단한 대상을 조회합니다.\n", - "operationId": "getBlockList", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseListBlockMemberDTO" - } - } - } - } - } - } - }, - "/admin/partner-recommend": { - "get": { - "tags": [ - "Admin" - ], - "summary": "제휴업체 추천 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed80f5b05cffcfecef9c24?source=copy_link)\n- 현재 로그인 한 관리자와 제휴하지 않은 제휴업체 중 한 곳을 랜덤으로 조회합니다.\n\n**Response:**\n - 성공 시 200(OK)과 `RandomPartnerResponse` 객체 반환\n - `partnerId` (Long): 제휴업체 ID\n - `partnerAddress` (String): 제휴업체 주소\n - `partnerDetailAddress` (String): 제휴업체 상세주소\n - `partnerName` (String): 제휴업체 상호명\n - `partnerUrl` (String): 제휴업체 카카오맵 URL\n - `partnerPhone` (String): 제휴업체 전화번호\n", - "operationId": "randomPartnerRecommend", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseAdminResponseDTO" - } - } - } - } - } - } - }, - "/admin/dashBoard": { - "get": { - "tags": [ - "Admin Dashboard" - ], - "summary": "누적 가입자 수 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-24c1197c19ed8062be94fc08619b760f)\n- 관리자(Admin) 권한으로 접근하여 현재까지의 총 누적 가입자 수를 조회합니다.", - "operationId": "getCountAdmin", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCountAdminAuthResponseDTO" - } - } - } - } - } - } - }, - "/admin/dashBoard/usage": { - "get": { - "tags": [ - "Admin Dashboard" - ], - "summary": "제휴업체 누적 사용 수 내림차순 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-24e1197c19ed802b92eff5d4dc4dbe82)\n- 모든 제휴 업체의 누적 사용 현황을 사용량 내림차순 리스트로 반환합니다.", - "operationId": "getUsageList", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCountUsageListResponseDTO" - } - } - } - } - } - } - }, - "/admin/dashBoard/top": { - "get": { - "tags": [ - "Admin Dashboard" - ], - "summary": "제휴업체 누적별 1위 업체 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_1-2ef1197c19ed8010a49ce6313d137b4f)\n- 제휴 이용 횟수가 가장 많은 1위 업체의 정보를 조회합니다.", - "operationId": "getTopUsage", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCountUsageResponseDTO" - } - } - } - } - } - } - }, - "/admin/dashBoard/new": { - "get": { - "tags": [ - "Admin Dashboard" - ], - "summary": "신규 한 달 가입자 수 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-24c1197c19ed805db80fca98c38849d1)\n- 이번 달(매달 1일 초기화) 기준 신규 가입한 사용자 수를 조회합니다.", - "operationId": "getNewStudentCountAdmin", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseNewCountAdminResponseDTO" - } - } - } - } - } - } - }, - "/admin/dashBoard/countUser": { - "get": { - "tags": [ - "Admin Dashboard" - ], - "summary": "오늘 제휴 사용자 수 조회 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-24e1197c19ed80a283b1c336a1c3df72)\n- 금일 제휴 서비스를 이용한 총 사용자 수를 조회합니다.", - "operationId": "getCountUser", - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseCountUsagePersonResponseDTO" - } - } - } - } - } - } - }, - "/reviews/{reviewId}": { - "delete": { - "tags": [ - "Review" - ], - "summary": "내가 쓴 리뷰 삭제 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2241197c19ed81a58e93c9ba56f6cb9a)\n- 본인이 작성한 리뷰를 ID를 기반으로 삭제합니다.", - "operationId": "deleteReview", - "parameters": [ - { - "name": "reviewId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseDeleteReviewResponseDTO" - } - } - } - } - } - } - }, - "/partnership/proposal/delete/{paperId}": { - "delete": { - "tags": [ - "Partnership" - ], - "summary": "제휴 제안서 삭제 API", - "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed80e58d30c469e4ba3146)\n- paperId와 관련된 모든 내용을 삭제합니다.\n- 성공 시 200(OK) 반환.\n\n**Parameters:**\n - `paperId` (Long, required): 삭제할 제안서 ID\n", - "operationId": "deletePartnership", - "parameters": [ - { - "name": "paperId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseVoid" - } - } - } - } - } - } - }, - "/device-tokens/{tokenId}": { - "delete": { - "tags": [ - "Device Token" - ], - "summary": "디바이스 토큰 등록 해제 API", - "description": "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed80b8b26be9e01d24c929?source=copy_link)\n- 로그아웃/탈퇴 시 호출해 디바이스 토큰 등록을 해제합니다.\n- 자신의 토큰만 해제가 가능합니다.\n\n**Path Variable:**\n- `tokenId` (Long, required): 해제할 디바이스 토큰 ID\n\n**Response:**\n- 성공 시 200(OK)과 성공 메시지 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 403(FORBIDDEN): 다른 사용자의 토큰 해제 시도\n- 404(NOT_FOUND): 존재하지 않는 토큰 ID", - "operationId": "unregister", - "parameters": [ - { - "name": "tokenId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseString" - } - } - } - } - } - } - }, - "/chat/unblock": { - "delete": { - "tags": [ - "Chatting" - ], - "summary": "상대방 차단 해제 API", - "description": "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed80b6a93fcbe277fc934c?pvs=74)\n- 상대방을 차단 해제합니다. 다시 메시지를 주고받을 수 있습니다.\n\n**Request Parameter:**\n- opponentId (Long, required): 상대방 ID\n", - "operationId": "unblock", - "parameters": [ - { - "name": "opponentId", - "in": "query", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseBlockMemberDTO" - } - } - } - } - } - } - }, - "/chat/rooms/{roomId}/leave": { - "delete": { - "tags": [ - "Chatting" - ], - "summary": "채팅방 나가기 API", - "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed800eab45c35073761c97?v=2241197c19ed8134b64f000cc26c5d31&p=2371197c19ed8079a6e1c2331cb4f534&pm=s)\n- 채팅방을 나갑니다.\n- 참여자가 2명이면 채팅방이 살아있지만, 이미 한 명이 나갔다면 채팅방이 삭제됩니다.\n\n**Path Variable:**\n- roomId (Long, required): 채팅방 ID\n", - "operationId": "leaveChattingRoom", - "parameters": [ - { - "name": "roomId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "*/*": { - "schema": { - "$ref": "#/components/schemas/BaseResponseLeaveChattingRoomResponseDTO" - } - } - } - } - } - } - } - }, - "components": { - "schemas": { - "BaseResponseNotificationSettingsResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/NotificationSettingsResponseDTO" - } - } - }, - "NotificationSettingsResponseDTO": { - "type": "object", - "properties": { - "settings": { - "type": "object", - "additionalProperties": { - "type": "boolean" - } - } - } - }, - "BaseResponseProfileImageResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/ProfileImageResponseDTO" - } - } - }, - "ProfileImageResponseDTO": { - "type": "object", - "properties": { - "url": { - "type": "string", - "description": "업로드된 프로필 이미지 URL" - } - } - }, - "TemporaryQrRequestDTO": { - "type": "object", - "properties": { - "adminName": { - "type": "string", - "description": "adminName을 입력해주세요" - }, - "sort": { - "type": "string", - "description": "프론트 단에서 enum을 정의하여 REVIEW/SUGGEST 둘중 하나로 넘겨주세요", - "enum": [ - "REVIEW", - "SUGGEST" - ] - } - }, - "required": [ - "sort" - ] - }, - "BaseResponseVoid": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "object" - } - } - }, - "WriteSuggestionRequestDTO": { - "type": "object", - "properties": { - "adminId": { - "type": "integer", - "format": "int64", - "description": "건의 대상 관리자 ID", - "example": 1 - }, - "storeName": { - "type": "string", - "description": "희망 가게 이름", - "example": "스타벅스 숭실대점" - }, - "benefit": { - "type": "string", - "description": "희망 혜택", - "example": "아메리카노 10% 할인" - } - }, - "required": [ - "adminId", - "benefit", - "storeName" - ] - }, - "BaseResponseWriteSuggestionResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/WriteSuggestionResponseDTO" - } - } - }, - "WriteSuggestionResponseDTO": { - "type": "object", - "properties": { - "suggestionId": { - "type": "integer", - "format": "int64", - "description": "건의 ID", - "example": 1 - }, - "userId": { - "type": "integer", - "format": "int64", - "description": "제안인 ID", - "example": 10 - }, - "adminId": { - "type": "integer", - "format": "int64", - "description": "건의 대상 관리자 ID", - "example": 1 - }, - "storeName": { - "type": "string", - "description": "희망 가게 이름", - "example": "스타벅스 숭실대점" - }, - "suggestionBenefit": { - "type": "string", - "description": "희망 혜택", - "example": "아메리카노 10% 할인" - } - }, - "required": [ - "adminId", - "storeName", - "suggestionBenefit", - "suggestionId", - "userId" - ] - }, - "BaseResponseString": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "string" - } - } - }, - "WriteReviewRequestDTO": { - "type": "object", - "properties": { - "content": { - "type": "string", - "description": "리뷰 내용", - "example": "정말 맛있었어요!" - }, - "rate": { - "type": "integer", - "format": "int32", - "description": "별점 (1-5)", - "example": 5, - "maximum": 5, - "minimum": 1 - }, - "storeId": { - "type": "integer", - "format": "int64", - "description": "가게 ID", - "example": 3 - }, - "partnerId": { - "type": "integer", - "format": "int64", - "description": "파트너 ID", - "example": 2 - }, - "partnershipUsageId": { - "type": "integer", - "format": "int64" - }, - "adminName": { - "type": "string" - } - } - }, - "BaseResponseWriteReviewResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/WriteReviewResponseDTO" - } - } - }, - "WriteReviewResponseDTO": { - "type": "object", - "properties": { - "reviewId": { - "type": "integer", - "format": "int64" - }, - "content": { - "type": "string" - }, - "rate": { - "type": "integer", - "format": "int32" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "memberId": { - "type": "integer", - "format": "int64" - }, - "reviewImageUrls": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "CreateContentReportRequest": { - "type": "object", - "properties": { - "targetType": { - "type": "string", - "enum": [ - "STUDENT_USER", - "REVIEW", - "SUGGESTION" - ] - }, - "targetId": { - "type": "integer", - "format": "int64" - }, - "reportType": { - "type": "string", - "enum": [ - "STUDENT_USER_SPAM", - "STUDENT_USER_INAPPROPRIATE_CONTENT", - "STUDENT_USER_HARASSMENT", - "STUDENT_USER_FRAUD", - "STUDENT_USER_PRIVACY_VIOLATION", - "STUDENT_USER_OTHER", - "REVIEW_INAPPROPRIATE_CONTENT", - "REVIEW_FALSE_INFORMATION", - "REVIEW_SPAM", - "SUGGESTION_INAPPROPRIATE_CONTENT", - "SUGGESTION_FALSE_INFORMATION", - "SUGGESTION_SPAM" - ] - } - }, - "required": [ - "reportType", - "targetId", - "targetType" - ] - }, - "BaseResponseCreateReportResponse": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CreateReportResponse" - } - } - }, - "CreateReportResponse": { - "type": "object", - "properties": { - "reportId": { - "type": "integer", - "format": "int64" - } - } - }, - "CreateStudentReportRequest": { - "type": "object", - "properties": { - "targetType": { - "type": "string", - "enum": [ - "STUDENT_USER", - "REVIEW", - "SUGGESTION" - ] - }, - "targetId": { - "type": "integer", - "format": "int64" - }, - "reportType": { - "type": "string", - "enum": [ - "STUDENT_USER_SPAM", - "STUDENT_USER_INAPPROPRIATE_CONTENT", - "STUDENT_USER_HARASSMENT", - "STUDENT_USER_FRAUD", - "STUDENT_USER_PRIVACY_VIOLATION", - "STUDENT_USER_OTHER", - "REVIEW_INAPPROPRIATE_CONTENT", - "REVIEW_FALSE_INFORMATION", - "REVIEW_SPAM", - "SUGGESTION_INAPPROPRIATE_CONTENT", - "SUGGESTION_FALSE_INFORMATION", - "SUGGESTION_SPAM" - ] - } - }, - "required": [ - "reportType", - "targetId", - "targetType" - ] - }, - "PartnershipFinalRequestDTO": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64", - "description": "storeId 입력" - }, - "adminId": { - "type": "integer", - "format": "int64", - "description": "adminId 입력" - }, - "tableNumber": { - "type": "string", - "description": "00~99 사이의 tableNumber를 입력해주세요" - }, - "adminName": { - "type": "string", - "description": "@@학생회 이름 그대로 입력해주세요" - }, - "placeName": { - "type": "string", - "description": "가게 명을 입력해주세요" - }, - "partnershipContent": { - "type": "string", - "description": "제휴 항목을 그대로 입력해주세요" - }, - "contentId": { - "type": "integer", - "format": "int64", - "description": "제휴 콘텐츠 아이디를 입력해주세요" - }, - "discount": { - "type": "integer", - "format": "int64" - }, - "userIds": { - "type": "array", - "description": "함께 인증한 유저들의 아이디를 입력해주세요(없을 시 공란)", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - "required": [ - "adminId", - "adminName", - "contentId", - "partnershipContent", - "placeName", - "storeId", - "tableNumber" - ] - }, - "PartnershipDraftRequestDTO": { - "type": "object", - "properties": { - "partnerId": { - "type": "integer", - "format": "int64", - "description": "제휴 제안서를 작성할 제휴업체 ID", - "example": 101 - } - }, - "required": [ - "partnerId" - ] - }, - "BaseResponsePartnershipDraftResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PartnershipDraftResponseDTO" - } - } - }, - "PartnershipDraftResponseDTO": { - "type": "object", - "properties": { - "paperId": { - "type": "integer", - "format": "int64", - "description": "생성된 제안서 ID", - "example": 1001 - } - }, - "required": [ - "paperId" - ] - }, - "ManualPartnershipRequestDTO": { - "type": "object", - "properties": { - "storeName": { - "type": "string", - "description": "가게 이름", - "example": "역전할머니맥주 숭실대점" - }, - "selectedPlace": { - "$ref": "#/components/schemas/SelectedPlacePayload", - "description": "선택된 장소 정보 (카카오맵 검색 결과)" - }, - "storeDetailAddress": { - "type": "string", - "description": "가게 상세주소", - "example": "2층" - }, - "partnershipPeriodStart": { - "type": "string", - "format": "date", - "description": "제휴 시작일", - "example": "2024-01-01" - }, - "partnershipPeriodEnd": { - "type": "string", - "format": "date", - "description": "제휴 마감일", - "example": "2024-12-31" - }, - "options": { - "type": "array", - "description": "제휴 옵션 목록", - "items": { - "$ref": "#/components/schemas/PartnershipOptionRequestDTO" - } - } - }, - "required": [ - "options", - "partnershipPeriodEnd", - "partnershipPeriodStart", - "selectedPlace", - "storeName" - ] - }, - "PartnershipGoodsRequestDTO": { - "type": "object", - "properties": { - "goodsName": { - "type": "string", - "description": "서비스 제공 항목명", - "example": "아메리카노" - } - } - }, - "PartnershipOptionRequestDTO": { - "type": "object", - "properties": { - "optionType": { - "type": "string", - "description": "제공 서비스 종류 (SERVICE: 서비스 제공, DISCOUNT: 할인)", - "enum": [ - "SERVICE", - "DISCOUNT" - ], - "example": "SERVICE" - }, - "criterionType": { - "type": "string", - "description": "서비스 제공 기준 (PRICE: 금액, HEADCOUNT: 인원)", - "enum": [ - "PRICE", - "HEADCOUNT" - ], - "example": "HEADCOUNT" - }, - "anotherType": { - "type": "boolean", - "description": "기타 제공 서비스 여부", - "example": false - }, - "people": { - "type": "integer", - "format": "int32", - "description": "서비스 제공 기준 인원 수", - "example": 2 - }, - "cost": { - "type": "integer", - "format": "int64", - "description": "서비스 제공 기준 금액", - "example": 10000 - }, - "category": { - "type": "string", - "description": "서비스 카테고리 (서비스 제공 항목이 여러 개일 때 작성)", - "example": "음료" - }, - "discountRate": { - "type": "integer", - "format": "int64", - "description": "할인율", - "example": 10 - }, - "note": { - "type": "string", - "description": "기타 유형 제휴 옵션 문구", - "example": "웰컴 드링크 제공" - }, - "goods": { - "type": "array", - "description": "서비스 제공 항목 목록", - "items": { - "$ref": "#/components/schemas/PartnershipGoodsRequestDTO" - } - } - }, - "required": [ - "anotherType", - "criterionType", - "optionType" - ] - }, - "SelectedPlacePayload": { - "type": "object", - "properties": { - "placeId": { - "type": "string", - "description": "장소 ID", - "example": 12345678 - }, - "name": { - "type": "string", - "description": "장소 이름", - "example": "숭실대학교" - }, - "address": { - "type": "string", - "description": "장소 지번 주소", - "example": "서울특별시 동작구 상도로 369" - }, - "roadAddress": { - "type": "string", - "description": "장소 도로명 주소", - "example": "서울특별시 동작구 상도로 369" - }, - "latitude": { - "type": "number", - "format": "double", - "description": "장소 위도", - "example": 37.5 - }, - "longitude": { - "type": "number", - "format": "double", - "description": "장소 경도", - "example": 126.96 - } - } - }, - "BaseResponseManualPartnershipResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/ManualPartnershipResponseDTO" - } - } - }, - "ManualPartnershipResponseDTO": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64", - "description": "가게 ID", - "example": 201 - }, - "storeCreated": { - "type": "boolean", - "description": "가게가 DB에 신규 생성되었는지 여부", - "example": false - }, - "storeActivated": { - "type": "boolean", - "description": "가게가 재활성화되었는지 여부", - "example": false - }, - "status": { - "type": "string", - "description": "제휴 제안서의 상태", - "example": "SUSPEND" - }, - "contractImageUrl": { - "type": "string", - "description": "계약서 파일 URL", - "example": "https://example.com/contract.jpg" - }, - "partnership": { - "$ref": "#/components/schemas/WritePartnershipResponseDTO", - "description": "제휴 제안서 상세 정보" - } - }, - "required": [ - "contractImageUrl", - "partnership", - "status", - "storeId" - ] - }, - "PartnershipGoodsResponseDTO": { - "type": "object", - "properties": { - "goodsId": { - "type": "integer", - "format": "int64", - "description": "서비스 제공 항목 ID", - "example": 501 - }, - "goodsName": { - "type": "string", - "description": "서비스 제공 항목명", - "example": "아메리카노" - } - }, - "required": [ - "goodsId", - "goodsName" - ] - }, - "PartnershipOptionResponseDTO": { - "type": "object", - "properties": { - "optionType": { - "type": "string", - "description": "제공 서비스 종류 (SERVICE: 서비스 제공, DISCOUNT: 할인)", - "enum": [ - "SERVICE", - "DISCOUNT" - ], - "example": "SERVICE" - }, - "criterionType": { - "type": "string", - "description": "서비스 제공 기준 (PRICE: 금액, HEADCOUNT: 인원)", - "enum": [ - "PRICE", - "HEADCOUNT" - ], - "example": "HEADCOUNT" - }, - "anotherType": { - "type": "boolean", - "description": "기타 제공 서비스 여부", - "example": false - }, - "people": { - "type": "integer", - "format": "int32", - "description": "서비스 제공 기준 인원 수", - "example": 2 - }, - "cost": { - "type": "integer", - "format": "int64", - "description": "서비스 제공 기준 금액", - "example": 10000 - }, - "note": { - "type": "string", - "description": "기타 유형 제휴 옵션 문구", - "example": "웰컴 드링크 제공" - }, - "category": { - "type": "string", - "description": "서비스 카테고리 (서비스 제공 항목이 여러 개일 때 작성)", - "example": "음료" - }, - "discountRate": { - "type": "integer", - "format": "int64", - "description": "할인율", - "example": 10 - }, - "goods": { - "type": "array", - "description": "서비스 제공 항목 목록", - "items": { - "$ref": "#/components/schemas/PartnershipGoodsResponseDTO" - } - } - }, - "required": [ - "anotherType", - "criterionType", - "optionType" - ] - }, - "WritePartnershipResponseDTO": { - "type": "object", - "properties": { - "partnershipId": { - "type": "integer", - "format": "int64", - "description": "제안서 ID", - "example": 1001 - }, - "partnershipPeriodStart": { - "type": "string", - "format": "date", - "description": "제휴 시작일", - "example": "2024-01-01" - }, - "partnershipPeriodEnd": { - "type": "string", - "format": "date", - "description": "제휴 마감일", - "example": "2024-12-31" - }, - "adminId": { - "type": "integer", - "format": "int64", - "description": "관리자 ID", - "example": 101 - }, - "partnerId": { - "type": "integer", - "format": "int64", - "description": "제휴업체 ID", - "example": 201 - }, - "storeId": { - "type": "integer", - "format": "int64", - "description": "가게 ID", - "example": 301 - }, - "storeName": { - "type": "string", - "description": "가게 이름", - "example": "역전할머니맥주 숭실대점" - }, - "adminName": { - "type": "string", - "description": "관리자 이름", - "example": "숭실대학교 총학생회" - }, - "isActivated": { - "type": "string", - "description": "제안서 활성화 여부", - "enum": [ - "ACTIVE", - "INACTIVE", - "SUSPEND", - "BLANK" - ], - "example": "SUSPEND" - }, - "options": { - "type": "array", - "description": "제휴 옵션 목록", - "items": { - "$ref": "#/components/schemas/PartnershipOptionResponseDTO" - } - } - }, - "required": [ - "adminId", - "adminName", - "isActivated", - "options", - "partnershipId", - "partnershipPeriodEnd", - "partnershipPeriodStart", - "storeId", - "storeName" - ] - }, - "QueueNotificationRequestDTO": { - "type": "object", - "properties": { - "receiverId": { - "type": "integer", - "format": "int64", - "description": "알림을 받을 멤버 ID", - "example": 1 - }, - "type": { - "type": "string", - "description": "알림 타입 (CHAT, PARTNER_SUGGESTION, ORDER, PARTNER_PROPOSAL)", - "example": "CHAT" - }, - "content": { - "type": "string", - "description": "알림 내용", - "example": "새로운 메시지가 있습니다." - }, - "title": { - "type": "string", - "description": "알림 제목", - "example": "채팅 알림" - }, - "deeplink": { - "type": "string", - "description": "앱 내 이동할 경로 (deeplink)", - "example": "app://chat/10" - }, - "roomId": { - "type": "integer", - "format": "int64", - "description": "채팅방 ID", - "example": 101 - }, - "senderName": { - "type": "string", - "description": "보낸 사람 이름", - "example": "홍길동" - }, - "message": { - "type": "string", - "description": "메시지 내용", - "example": "안녕하세요! 오늘 일정 확인 부탁드려요." - }, - "suggestionId": { - "type": "integer", - "format": "int64", - "description": "제휴 제안 ID", - "example": 2001 - }, - "orderId": { - "type": "integer", - "format": "int64", - "description": "주문 ID", - "example": 3001 - }, - "table_num": { - "type": "string", - "description": "테이블 번호", - "example": 11 - }, - "paper_content": { - "type": "string", - "description": "계약서 내용", - "example": "20,000원 이상 구매 시 10% 할인" - }, - "proposalId": { - "type": "integer", - "format": "int64", - "description": "제휴 제안 ID", - "example": 4001 - }, - "partner_name": { - "type": "string", - "description": "파트너 이름", - "example": "역전할머니맥주 송신대점" - }, - "refId": { - "type": "integer", - "format": "int64", - "description": "참조 ID (타입별로 roomId/orderId 등 대신 사용할 수 있음)", - "example": 9999 - } - }, - "required": [ - "receiverId", - "type" - ] - }, - "InquiryCreateRequestDTO": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "문의 제목", - "example": "상호명 변경 요청드립니다." - }, - "content": { - "type": "string", - "description": "문의 내용", - "example": "안녕하세요. 역할맥입니다. 상호명을 변경하고 싶습니다." - }, - "email": { - "type": "string", - "description": "문의자 이메일", - "example": "assu@gmail.com" - } - }, - "required": [ - "content", - "email", - "title" - ] - }, - "BaseResponseLong": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "integer", - "format": "int64" - } - } - }, - "CreateChatRoomRequestDTO": { - "type": "object", - "description": "채팅방 생성 요청 DTO", - "properties": { - "adminId": { - "type": "integer", - "format": "int64", - "description": "사장님 id", - "example": 2 - }, - "partnerId": { - "type": "integer", - "format": "int64", - "description": "파트너 id", - "example": 12 - } - } - }, - "BaseResponseCreateChatRoomResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CreateChatRoomResponseDTO" - } - } - }, - "CreateChatRoomResponseDTO": { - "type": "object", - "properties": { - "roomId": { - "type": "integer", - "format": "int64" - }, - "adminViewName": { - "type": "string" - }, - "partnerViewName": { - "type": "string" - }, - "isNew": { - "type": "boolean" - } - } - }, - "BlockMemberRequestDTO": { - "type": "object", - "description": "채팅 차단 DTO", - "properties": { - "opponentId": { - "type": "integer", - "format": "int64", - "description": "차단할 사용자 ID", - "example": 12 - } - } - }, - "BaseResponseBlockMemberDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/BlockMemberDTO" - } - } - }, - "BlockMemberDTO": { - "type": "object", - "properties": { - "memberId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string" - }, - "blockDate": { - "type": "string", - "format": "date-time" - } - } - }, - "CertificationGroupRequestDTO": { - "type": "object", - "properties": { - "people": { - "type": "integer", - "format": "int32", - "description": "1명 이상의 사람 수를 입력해주세요" - }, - "storeId": { - "type": "integer", - "format": "int64", - "description": "storeId를 입력해주세요" - }, - "adminId": { - "type": "integer", - "format": "int64", - "description": "adminId를 입력해주세요" - }, - "tableNumber": { - "type": "integer", - "format": "int32", - "description": "00~99 사이의 tableNumber를 입력해주세요" - } - }, - "required": [ - "adminId", - "people", - "storeId", - "tableNumber" - ] - }, - "BaseResponseCertificationResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CertificationResponseDTO" - } - } - }, - "CertificationResponseDTO": { - "type": "object", - "properties": { - "sessionId": { - "type": "integer", - "format": "int64", - "description": "qr에 넣을 세션 아이디를 반환합니다." - } - } - }, - "CertificationPersonalRequestDTO": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64", - "description": "storeId를 입력해주세요" - }, - "adminId": { - "type": "integer", - "format": "int64", - "description": "adminId를 입력해주세요" - }, - "tableNumber": { - "type": "integer", - "format": "int32", - "description": "00~99 사이의 tableNumber를 입력해주세요" - } - }, - "required": [ - "adminId", - "storeId", - "tableNumber" - ] - }, - "BaseResponseRefreshResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/RefreshResponseDTO" - } - } - }, - "RefreshResponseDTO": { - "type": "object", - "description": "액세스 토큰 갱신 응답", - "properties": { - "memberId": { - "type": "integer", - "format": "int64", - "description": "회원 ID", - "example": 123 - }, - "newAccess": { - "type": "string", - "description": "새로운 액세스 토큰", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - }, - "newRefresh": { - "type": "string", - "description": "새로운 리프레시 토큰", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - } - } - }, - "USaintAuthRequestDTO": { - "type": "object", - "description": "유세인트 인증 요청", - "properties": { - "sToken": { - "type": "string", - "description": "유세인트 sToken", - "example": "Vy3zFySFx5FASz175Kx7AzKyuSFQEgQ..." - }, - "sIdno": { - "type": "string", - "description": "유세인트 sIdno", - "example": 20211438 - } - }, - "required": [ - "sIdno", - "sToken" - ] - }, - "BaseResponseUSaintAuthResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/USaintAuthResponseDTO" - } - } - }, - "USaintAuthResponseDTO": { - "type": "object", - "description": "유세인트 인증 응답", - "properties": { - "studentNumber": { - "type": "string", - "description": "학번", - "example": 20211438 - }, - "name": { - "type": "string", - "description": "이름", - "example": "홍길동" - }, - "enrollmentStatus": { - "type": "string", - "description": "학적 상태", - "example": "재학" - }, - "yearSemester": { - "type": "string", - "description": "학년/학기", - "example": "4학년 1학기" - }, - "majorStr": { - "type": "string", - "description": "전공/학과" - } - } - }, - "StudentTokenAuthPayloadDTO": { - "type": "object", - "description": "학생 토큰 인증 페이로드", - "properties": { - "sToken": { - "type": "string", - "description": "유세인트 sToken", - "example": "Vy3zFySFx5FASz175Kx7AzKyuSFQEgQ..." - }, - "sIdno": { - "type": "string", - "description": "유세인트 sIdno", - "example": 20211438 - }, - "university": { - "type": "string", - "description": "대학교", - "enum": [ - "SSU" - ], - "example": "SSU" - } - }, - "required": [ - "sIdno", - "sToken" - ] - }, - "StudentTokenSignUpRequestDTO": { - "type": "object", - "description": "학생 토큰 회원가입 요청", - "properties": { - "marketingAgree": { - "type": "boolean", - "description": "마케팅 수신 동의", - "example": true - }, - "locationAgree": { - "type": "boolean", - "description": "위치 정보 수집 동의", - "example": true - }, - "studentTokenAuth": { - "$ref": "#/components/schemas/StudentTokenAuthPayloadDTO", - "description": "학생 토큰 인증 정보" - } - }, - "required": [ - "locationAgree", - "marketingAgree", - "studentTokenAuth" - ] - }, - "BaseResponseSignUpResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/SignUpResponseDTO" - } - } - }, - "SignUpResponseDTO": { - "type": "object", - "description": "회원가입 성공 응답", - "properties": { - "memberId": { - "type": "integer", - "format": "int64", - "description": "회원 ID", - "example": 123 - }, - "role": { - "type": "string", - "description": "회원 역할", - "enum": [ - "STUDENT", - "ADMIN", - "PARTNER" - ], - "example": "STUDENT" - }, - "status": { - "type": "string", - "description": "회원 상태", - "enum": [ - "ACTIVE", - "INACTIVE", - "SUSPEND", - "BLANK" - ], - "example": "ACTIVE" - }, - "tokens": { - "$ref": "#/components/schemas/TokensDTO", - "description": "액세스 토큰/리프레시 토큰" - }, - "basicInfo": { - "$ref": "#/components/schemas/UserBasicInfoDTO", - "description": "사용자 기본 정보 (캐싱용)" - } - } - }, - "TokensDTO": { - "type": "object", - "description": "JWT 토큰 정보", - "properties": { - "accessToken": { - "type": "string", - "description": "액세스 토큰", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - }, - "refreshToken": { - "type": "string", - "description": "리프레시 토큰", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - } - } - }, - "UserBasicInfoDTO": { - "type": "object", - "description": "사용자 기본 정보", - "properties": { - "name": { - "type": "string", - "description": "이름/업체명/단체명", - "example": "홍길동" - }, - "university": { - "type": "string", - "description": "대학교", - "example": "숭실대학교" - }, - "department": { - "type": "string", - "description": "단과대", - "example": "IT공과대학" - }, - "major": { - "type": "string", - "description": "전공/학과", - "example": "소프트웨어학부" - } - } - }, - "BaseResponseLoginResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/LoginResponseDTO" - } - } - }, - "LoginResponseDTO": { - "type": "object", - "description": "로그인 성공 응답", - "properties": { - "memberId": { - "type": "integer", - "format": "int64", - "description": "회원 ID", - "example": 123 - }, - "role": { - "type": "string", - "description": "회원 역할", - "enum": [ - "STUDENT", - "ADMIN", - "PARTNER" - ], - "example": "STUDENT" - }, - "status": { - "type": "string", - "description": "회원 상태", - "enum": [ - "ACTIVE", - "INACTIVE", - "SUSPEND", - "BLANK" - ], - "example": "SUSPEND" - }, - "tokens": { - "$ref": "#/components/schemas/TokensDTO", - "description": "액세스 토큰/리프레시 토큰", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - }, - "basicInfo": { - "$ref": "#/components/schemas/UserBasicInfoDTO", - "description": "사용자 기본 정보 (캐싱용)" - } - } - }, - "PhoneAuthVerifyRequestDTO": { - "type": "object", - "description": "휴대폰 인증번호 검증 요청", - "properties": { - "phoneNumber": { - "type": "string", - "description": "인증받을 휴대폰 번호", - "example": "01012345678", - "pattern": "^010\\d{8}$" - }, - "authNumber": { - "type": "string", - "description": "발송받은 인증번호(OTP)", - "example": 123456 - } - }, - "required": [ - "authNumber", - "phoneNumber" - ] - }, - "PhoneAuthSendRequestDTO": { - "type": "object", - "description": "휴대폰 번호 중복가입 확인 및 인증번호 발송 요청", - "properties": { - "phoneNumber": { - "type": "string", - "description": "인증번호를 받을 휴대폰 번호", - "example": "01012345678", - "pattern": "^010\\d{8}$" - } - }, - "required": [ - "phoneNumber" - ] - }, - "CommonAuthPayloadDTO": { - "type": "object", - "description": "공통 인증 정보 페이로드", - "properties": { - "email": { - "type": "string", - "description": "이메일 주소", - "example": "user@example.com" - }, - "password": { - "type": "string", - "description": "비밀번호(평문)", - "example": "P@ssw0rd!", - "maxLength": 72, - "minLength": 8 - }, - "department": { - "type": "string", - "description": "단과대", - "enum": [ - "HUMANITIES", - "NATURAL_SCIENCE", - "LAW", - "SOCIAL_SCIENCE", - "ECONOMICS", - "BUSINESS", - "ENGINEERING", - "IT", - "LIBERAL_STUDIES", - "AI" - ], - "example": "IT공과대학" - }, - "major": { - "type": "string", - "description": "전공/학과", - "enum": [ - "CHRISTIAN_STUDIES", - "KOREAN_LITERATURE", - "ENGLISH_LITERATURE", - "GERMAN_LITERATURE", - "FRENCH_LITERATURE", - "CHINESE_LITERATURE", - "JAPANESE_LITERATURE", - "PHILOSOPHY", - "HISTORY", - "CREATIVE_ARTS", - "SPORTS", - "MATHEMATICS", - "CHEMISTRY", - "BIOMEDICAL_SYSTEMS", - "PHYSICS", - "STATISTICS_ACTUARIAL", - "LAW", - "INTERNATIONAL_LAW", - "SOCIAL_WELFARE", - "POLITICAL_SCIENCE", - "MEDIA_COMMUNICATION", - "PUBLIC_ADMINISTRATION", - "INFORMATION_SOCIETY", - "LIFELONG_EDUCATION", - "ECONOMICS", - "FINANCIAL_ECONOMICS", - "GLOBAL_TRADE", - "INTERNATIONAL_TRADE", - "BUSINESS_ADMINISTRATION", - "ACCOUNTING", - "VENTURE_MANAGEMENT", - "WELFARE_MANAGEMENT", - "VENTURE_SME", - "FINANCE", - "INNOVATION_MANAGEMENT", - "ACCOUNTING_TAX", - "CHEMICAL_ENGINEERING", - "ELECTRICAL_ENGINEERING", - "ARCHITECTURE", - "INDUSTRIAL_INFO_SYSTEMS", - "MECHANICAL_ENGINEERING", - "MATERIALS_SCIENCE", - "SOFTWARE", - "GLOBAL_MEDIA", - "COMPUTER_SCIENCE", - "ELECTRONIC_ENGINEERING", - "AI_CONVERGENCE", - "DIGITAL_MEDIA", - "LIBERAL_STUDIES", - "AI_SOFTWARE", - "INFORMATION_SECURITY" - ], - "example": "소프트웨어학부" - }, - "university": { - "type": "string", - "description": "대학교", - "enum": [ - "SSU" - ], - "example": "SSU" - } - }, - "required": [ - "email", - "password" - ] - }, - "CommonInfoPayloadDTO": { - "type": "object", - "description": "공통 정보 페이로드", - "properties": { - "name": { - "type": "string", - "description": "이름/업체명/단체명", - "example": "홍길동", - "maxLength": 50, - "minLength": 1 - }, - "detailAddress": { - "type": "string", - "description": "상세 주소", - "example": "101호", - "maxLength": 255, - "minLength": 0 - }, - "selectedPlace": { - "$ref": "#/components/schemas/SelectedPlacePayload", - "description": "선택된 장소 정보" - } - }, - "required": [ - "name", - "selectedPlace" - ] - }, - "PartnerSignUpRequestDTO": { - "type": "object", - "description": "JSON 형식의 제휴업체 가입 정보", - "properties": { - "phoneNumber": { - "type": "string", - "description": "휴대폰 번호", - "example": "01012345678", - "pattern": "^(01[016789])\\d{3,4}\\d{4}$" - }, - "marketingAgree": { - "type": "boolean", - "description": "마케팅 수신 동의", - "example": true - }, - "locationAgree": { - "type": "boolean", - "description": "위치 정보 수집 동의", - "example": true - }, - "commonAuth": { - "$ref": "#/components/schemas/CommonAuthPayloadDTO", - "description": "관리자/제휴업체공통 인증 정보" - }, - "commonInfo": { - "$ref": "#/components/schemas/CommonInfoPayloadDTO", - "description": "관리자/제휴업체 공통 정보" - } - }, - "required": [ - "commonAuth", - "commonInfo", - "locationAgree", - "marketingAgree" - ] - }, - "EmailVerificationCheckRequestDTO": { - "type": "object", - "description": "이메일 중복 확인 요청", - "properties": { - "email": { - "type": "string", - "description": "확인할 이메일 주소", - "example": "user@example.com" - } - }, - "required": [ - "email" - ] - }, - "CommonLoginRequestDTO": { - "type": "object", - "description": "파트너/관리자 공통 로그인 요청", - "properties": { - "email": { - "type": "string", - "description": "로그인 이메일", - "example": "user@example.com", - "maxLength": 255, - "minLength": 0 - }, - "password": { - "type": "string", - "description": "로그인 비밀번호(평문)", - "example": "P@ssw0rd!", - "maxLength": 64, - "minLength": 8 - } - }, - "required": [ - "email", - "password" - ] - }, - "AdminSignUpRequestDTO": { - "type": "object", - "description": "JSON 형식의 관리자 가입 정보", - "properties": { - "phoneNumber": { - "type": "string", - "description": "휴대폰 번호", - "example": "01012345678", - "pattern": "^(01[016789])\\d{3,4}\\d{4}$" - }, - "marketingAgree": { - "type": "boolean", - "description": "마케팅 수신 동의", - "example": true - }, - "locationAgree": { - "type": "boolean", - "description": "위치 정보 수집 동의", - "example": true - }, - "commonAuth": { - "$ref": "#/components/schemas/CommonAuthPayloadDTO", - "description": "관리자/제휴업체공통 인증 정보" - }, - "commonInfo": { - "$ref": "#/components/schemas/CommonInfoPayloadDTO", - "description": "관리자/제휴업체 공통 정보" - } - }, - "required": [ - "commonAuth", - "commonInfo", - "locationAgree", - "marketingAgree" - ] - }, - "AppReviewRequestDTO": { - "type": "object", - "description": "앱 리뷰 작성 요청", - "properties": { - "rate": { - "type": "integer", - "format": "int32", - "description": "별점 (1~5)", - "example": 5, - "maximum": 5, - "minimum": 1 - }, - "content": { - "type": "string", - "description": "후기 내용", - "example": "너무 좋아용~" - } - }, - "required": [ - "content", - "rate" - ] - }, - "PartnershipStatusUpdateRequestDTO": { - "type": "object", - "properties": { - "status": { - "type": "string", - "description": "제안서에 적용할 상태 (ACTIVE/SUSPEND/INACTIVE)", - "example": "ACTIVE" - } - }, - "required": [ - "status" - ] - }, - "BaseResponsePartnershipStatusUpdateResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PartnershipStatusUpdateResponseDTO" - } - } - }, - "PartnershipStatusUpdateResponseDTO": { - "type": "object", - "properties": { - "partnershipId": { - "type": "integer", - "format": "int64", - "description": "제안서 ID", - "example": 1001 - }, - "prevStatus": { - "type": "string", - "description": "변경 전 제안서 상태", - "example": "SUSPEND" - }, - "newStatus": { - "type": "string", - "description": "변경 후 제안서 상태", - "example": "ACTIVE" - }, - "changedAt": { - "type": "string", - "format": "date-time", - "description": "상태 변경 시간", - "example": "2024-06-15T10:30:00" - } - }, - "required": [ - "changedAt", - "newStatus", - "partnershipId", - "prevStatus" - ] - }, - "WritePartnershipRequestDTO": { - "type": "object", - "properties": { - "paperId": { - "type": "integer", - "format": "int64", - "description": "수정할 제안서 ID", - "example": 1001 - }, - "partnershipPeriodStart": { - "type": "string", - "format": "date", - "description": "제휴 시작일", - "example": "2024-01-01" - }, - "partnershipPeriodEnd": { - "type": "string", - "format": "date", - "description": "제휴 마감일", - "example": "2024-12-31" - }, - "options": { - "type": "array", - "description": "제휴 옵션 목록", - "items": { - "$ref": "#/components/schemas/PartnershipOptionRequestDTO" - } - } - }, - "required": [ - "options", - "paperId", - "partnershipPeriodEnd", - "partnershipPeriodStart" - ] - }, - "BaseResponseWritePartnershipResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/WritePartnershipResponseDTO" - } - } - }, - "InquiryAnswerRequestDTO": { - "type": "object", - "properties": { - "answer": { - "type": "string", - "description": "답변 내용", - "example": "안녕하세요. A:SSU 팀입니다." - } - }, - "required": [ - "answer" - ] - }, - "BaseResponseReadMessageResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/ReadMessageResponseDTO" - } - } - }, - "ReadMessageResponseDTO": { - "type": "object", - "properties": { - "roomId": { - "type": "integer", - "format": "int64" - }, - "readerId": { - "type": "integer", - "format": "int64" - }, - "readMessagesId": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - }, - "readCount": { - "type": "integer", - "format": "int32" - }, - "isRead": { - "type": "boolean" - } - } - }, - "BaseResponseListTemporaryQrResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TemporaryQrResponseDTO" - } - } - } - }, - "TemporaryQrResponseDTO": { - "type": "object", - "properties": { - "adminName": { - "type": "string" - }, - "sort": { - "type": "string", - "enum": [ - "REVIEW", - "SUGGEST" - ] - }, - "createdAt": { - "type": "string" - } - } - }, - "BaseResponseListGetSuggestionResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "array", - "items": { - "$ref": "#/components/schemas/GetSuggestionResponseDTO" - } - } - } - }, - "GetSuggestionResponseDTO": { - "type": "object", - "properties": { - "suggestionId": { - "type": "integer", - "format": "int64", - "description": "건의 ID", - "example": 1 - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "건의 작성일", - "example": "2026-01-04T12:00:00" - }, - "storeName": { - "type": "string", - "description": "희망 가게 이름", - "example": "스타벅스 숭실대점" - }, - "content": { - "type": "string", - "description": "건의 내용", - "example": "아메리카노 10% 할인" - }, - "studentMajor": { - "type": "string", - "description": "건의자의 학부/학과", - "enum": [ - "CHRISTIAN_STUDIES", - "KOREAN_LITERATURE", - "ENGLISH_LITERATURE", - "GERMAN_LITERATURE", - "FRENCH_LITERATURE", - "CHINESE_LITERATURE", - "JAPANESE_LITERATURE", - "PHILOSOPHY", - "HISTORY", - "CREATIVE_ARTS", - "SPORTS", - "MATHEMATICS", - "CHEMISTRY", - "BIOMEDICAL_SYSTEMS", - "PHYSICS", - "STATISTICS_ACTUARIAL", - "LAW", - "INTERNATIONAL_LAW", - "SOCIAL_WELFARE", - "POLITICAL_SCIENCE", - "MEDIA_COMMUNICATION", - "PUBLIC_ADMINISTRATION", - "INFORMATION_SOCIETY", - "LIFELONG_EDUCATION", - "ECONOMICS", - "FINANCIAL_ECONOMICS", - "GLOBAL_TRADE", - "INTERNATIONAL_TRADE", - "BUSINESS_ADMINISTRATION", - "ACCOUNTING", - "VENTURE_MANAGEMENT", - "WELFARE_MANAGEMENT", - "VENTURE_SME", - "FINANCE", - "INNOVATION_MANAGEMENT", - "ACCOUNTING_TAX", - "CHEMICAL_ENGINEERING", - "ELECTRICAL_ENGINEERING", - "ARCHITECTURE", - "INDUSTRIAL_INFO_SYSTEMS", - "MECHANICAL_ENGINEERING", - "MATERIALS_SCIENCE", - "SOFTWARE", - "GLOBAL_MEDIA", - "COMPUTER_SCIENCE", - "ELECTRONIC_ENGINEERING", - "AI_CONVERGENCE", - "DIGITAL_MEDIA", - "LIBERAL_STUDIES", - "AI_SOFTWARE", - "INFORMATION_SECURITY" - ], - "example": "COM" - }, - "enrollmentStatus": { - "type": "string", - "description": "재학 상태", - "enum": [ - "ENROLLED", - "LEAVE", - "GRADUATED" - ], - "example": "ENROLLED" - } - }, - "required": [ - "content", - "createdAt", - "enrollmentStatus", - "storeName", - "studentMajor", - "suggestionId" - ] - }, - "BaseResponseGetSuggestionAdminsDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/GetSuggestionAdminsDTO" - } - } - }, - "GetSuggestionAdminsDTO": { - "type": "object", - "properties": { - "adminId": { - "type": "integer", - "format": "int64", - "description": "총학생회 ID", - "example": 1 - }, - "adminName": { - "type": "string", - "description": "총학생회 이름", - "example": "숭실대학교 총학생회" - }, - "departId": { - "type": "integer", - "format": "int64", - "description": "단과대학 학생회 ID", - "example": 2 - }, - "departName": { - "type": "string", - "description": "단과대학 학생회 이름", - "example": "IT대학 학생회" - }, - "majorId": { - "type": "integer", - "format": "int64", - "description": "학부/학과 학생회 ID", - "example": 3 - }, - "majorName": { - "type": "string", - "description": "학부/학과 학생회 이름", - "example": "컴퓨터학부 학생회" - } - } - }, - "Pageable": { - "type": "object", - "properties": { - "page": { - "type": "integer", - "format": "int32", - "minimum": 0 - }, - "size": { - "type": "integer", - "format": "int32", - "minimum": 1 - }, - "sort": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "BaseResponsePageUsageDetail": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PageUsageDetail" - } - } - }, - "PageUsageDetail": { - "type": "object", - "properties": { - "totalPages": { - "type": "integer", - "format": "int32" - }, - "totalElements": { - "type": "integer", - "format": "int64" - }, - "size": { - "type": "integer", - "format": "int32" - }, - "content": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UsageDetail" - } - }, - "number": { - "type": "integer", - "format": "int32" - }, - "sort": { - "$ref": "#/components/schemas/SortObject" - }, - "first": { - "type": "boolean" - }, - "last": { - "type": "boolean" - }, - "pageable": { - "$ref": "#/components/schemas/PageableObject" - }, - "numberOfElements": { - "type": "integer", - "format": "int32" - }, - "empty": { - "type": "boolean" - } - } - }, - "PageableObject": { - "type": "object", - "properties": { - "offset": { - "type": "integer", - "format": "int64" - }, - "sort": { - "$ref": "#/components/schemas/SortObject" - }, - "paged": { - "type": "boolean" - }, - "pageSize": { - "type": "integer", - "format": "int32" - }, - "pageNumber": { - "type": "integer", - "format": "int32" - }, - "unpaged": { - "type": "boolean" - } - } - }, - "SortObject": { - "type": "object", - "properties": { - "empty": { - "type": "boolean" - }, - "unsorted": { - "type": "boolean" - }, - "sorted": { - "type": "boolean" - } - } - }, - "UsageDetail": { - "type": "object", - "properties": { - "adminName": { - "type": "string" - }, - "partnershipUsageId": { - "type": "integer", - "format": "int64" - }, - "storeName": { - "type": "string" - }, - "partnerId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "usedAt": { - "type": "string" - }, - "benefitDescription": { - "type": "string" - }, - "isReviewed": { - "type": "boolean" - } - } - }, - "BaseResponseListUsablePartnershipDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UsablePartnershipDTO" - } - } - } - }, - "UsablePartnershipDTO": { - "type": "object", - "properties": { - "partnershipId": { - "type": "integer", - "format": "int64" - }, - "adminName": { - "type": "string" - }, - "partnerName": { - "type": "string" - }, - "criterionType": { - "type": "string", - "enum": [ - "PRICE", - "HEADCOUNT" - ] - }, - "optionType": { - "type": "string", - "enum": [ - "SERVICE", - "DISCOUNT" - ] - }, - "people": { - "type": "integer", - "format": "int32" - }, - "cost": { - "type": "integer", - "format": "int64" - }, - "note": { - "type": "string" - }, - "paperId": { - "type": "integer", - "format": "int64" - }, - "category": { - "type": "string" - }, - "discountRate": { - "type": "integer", - "format": "int64" - } - } - }, - "BaseResponseCheckStampResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CheckStampResponseDTO" - } - } - }, - "CheckStampResponseDTO": { - "type": "object", - "properties": { - "userId": { - "type": "integer", - "format": "int64" - }, - "stamp": { - "type": "integer", - "format": "int32" - }, - "message": { - "type": "string" - } - } - }, - "BaseResponseMyPartnership": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/MyPartnership" - } - } - }, - "MyPartnership": { - "type": "object", - "properties": { - "serviceCount": { - "type": "integer", - "format": "int64" - }, - "details": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UsageDetail" - } - } - } - }, - "BaseResponsePaperResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PaperResponseDTO" - } - } - }, - "PaperContentResponseDTO": { - "type": "object", - "properties": { - "adminId": { - "type": "integer", - "format": "int64" - }, - "adminName": { - "type": "string" - }, - "paperContent": { - "type": "string" - }, - "contentId": { - "type": "integer", - "format": "int64" - }, - "goods": { - "type": "array", - "items": { - "type": "string" - } - }, - "people": { - "type": "integer", - "format": "int32" - }, - "cost": { - "type": "integer", - "format": "int64" - } - } - }, - "PaperResponseDTO": { - "type": "object", - "properties": { - "partnershipContents": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaperContentResponseDTO" - } - }, - "storeName": { - "type": "string" - }, - "storeId": { - "type": "integer", - "format": "int64" - } - } - }, - "BaseResponseStampRankingListDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/StampRankingListDTO" - } - } - }, - "StampRankingDTO": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "storeName": { - "type": "string" - }, - "stampCount": { - "type": "integer", - "format": "int64" - } - } - }, - "StampRankingListDTO": { - "type": "object", - "properties": { - "rankings": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StampRankingDTO" - } - } - } - }, - "BaseResponseWeeklyRankResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/WeeklyRankResponseDTO" - } - } - }, - "WeeklyRankResponseDTO": { - "type": "object", - "properties": { - "rank": { - "type": "integer", - "format": "int64" - }, - "usageCount": { - "type": "integer", - "format": "int64" - } - } - }, - "BaseResponseListWeeklyRankResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "array", - "items": { - "$ref": "#/components/schemas/WeeklyRankResponseDTO" - } - } - } - }, - "BaseResponseTodayBestResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/TodayBestResponseDTO" - } - } - }, - "TodayBestResponseDTO": { - "type": "object", - "properties": { - "bestStores": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "BaseResponsePageCheckReviewResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PageCheckReviewResponseDTO" - } - } - }, - "CheckReviewResponseDTO": { - "type": "object", - "properties": { - "reviewId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "affiliation": { - "type": "string" - }, - "storeName": { - "type": "string" - }, - "content": { - "type": "string" - }, - "rate": { - "type": "integer", - "format": "int32" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "reviewImageUrls": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "PageCheckReviewResponseDTO": { - "type": "object", - "properties": { - "totalPages": { - "type": "integer", - "format": "int32" - }, - "totalElements": { - "type": "integer", - "format": "int64" - }, - "size": { - "type": "integer", - "format": "int32" - }, - "content": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CheckReviewResponseDTO" - } - }, - "number": { - "type": "integer", - "format": "int32" - }, - "sort": { - "$ref": "#/components/schemas/SortObject" - }, - "first": { - "type": "boolean" - }, - "last": { - "type": "boolean" - }, - "pageable": { - "$ref": "#/components/schemas/PageableObject" - }, - "numberOfElements": { - "type": "integer", - "format": "int32" - }, - "empty": { - "type": "boolean" - } - } - }, - "BaseResponseStandardScoreResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/StandardScoreResponseDTO" - } - } - }, - "StandardScoreResponseDTO": { - "type": "object", - "properties": { - "score": { - "type": "number", - "format": "float" - } - } - }, - "BaseResponsePartnershipDetailResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PartnershipDetailResponseDTO" - } - } - }, - "PartnershipDetailResponseDTO": { - "type": "object", - "properties": { - "partnershipId": { - "type": "integer", - "format": "int64", - "description": "제안서 ID", - "example": 1001 - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "제안서 최종 수정 시간", - "example": "2024-06-15T10:30:00" - }, - "partnershipPeriodStart": { - "type": "string", - "format": "date", - "description": "제휴 시작일", - "example": "2024-01-01" - }, - "partnershipPeriodEnd": { - "type": "string", - "format": "date", - "description": "제휴 마감일", - "example": "2024-12-31" - }, - "adminId": { - "type": "integer", - "format": "int64", - "description": "관리자 ID", - "example": 101 - }, - "partnerId": { - "type": "integer", - "format": "int64", - "description": "제휴업체 ID", - "example": 201 - }, - "storeId": { - "type": "integer", - "format": "int64", - "description": "가게 ID", - "example": 301 - }, - "options": { - "type": "array", - "description": "제휴 옵션 목록", - "items": { - "$ref": "#/components/schemas/PartnershipOptionResponseDTO" - } - } - }, - "required": [ - "adminId", - "options", - "partnershipId", - "partnershipPeriodEnd", - "partnershipPeriodStart", - "storeId", - "updatedAt" - ] - }, - "BaseResponseListSuspendedPaperResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SuspendedPaperResponseDTO" - } - } - } - }, - "SuspendedPaperResponseDTO": { - "type": "object", - "properties": { - "paperId": { - "type": "integer", - "format": "int64", - "description": "제안서 ID", - "example": 1001 - }, - "partnerName": { - "type": "string", - "description": "제휴업체 이름", - "example": "역전할머니맥주 숭실대점" - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "제안서 생성 일자", - "example": "2024-01-01T09:00:00" - } - }, - "required": [ - "createdAt", - "paperId", - "partnerName" - ] - }, - "BaseResponsePageWritePartnershipResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PageWritePartnershipResponseDTO" - } - } - }, - "PageWritePartnershipResponseDTO": { - "type": "object", - "properties": { - "totalPages": { - "type": "integer", - "format": "int32" - }, - "totalElements": { - "type": "integer", - "format": "int64" - }, - "size": { - "type": "integer", - "format": "int32" - }, - "content": { - "type": "array", - "items": { - "$ref": "#/components/schemas/WritePartnershipResponseDTO" - } - }, - "number": { - "type": "integer", - "format": "int32" - }, - "sort": { - "$ref": "#/components/schemas/SortObject" - }, - "first": { - "type": "boolean" - }, - "last": { - "type": "boolean" - }, - "pageable": { - "$ref": "#/components/schemas/PageableObject" - }, - "numberOfElements": { - "type": "integer", - "format": "int32" - }, - "empty": { - "type": "boolean" - } - } - }, - "BaseResponsePartnerPartnershipCheckResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PartnerPartnershipCheckResponseDTO" - } - } - }, - "PartnerPartnershipCheckResponseDTO": { - "type": "object", - "properties": { - "paperId": { - "type": "integer", - "format": "int64", - "description": "제안서 ID", - "example": 1001 - }, - "isPartnered": { - "type": "boolean", - "description": "제휴 여부", - "example": true - }, - "status": { - "type": "string", - "description": "제휴 상태", - "example": "ACTIVE" - }, - "adminId": { - "type": "integer", - "format": "int64", - "description": "관리자 ID", - "example": 101 - }, - "adminName": { - "type": "string", - "description": "관리자 이름", - "example": "숭실대학교 총학생회" - }, - "adminAddress": { - "type": "string", - "description": "관리자 주소", - "example": "서울특별시 동작구 상도로" - } - }, - "required": [ - "adminAddress", - "adminId", - "adminName", - "paperId", - "status" - ] - }, - "AdminPartnershipCheckResponseDTO": { - "type": "object", - "properties": { - "paperId": { - "type": "integer", - "format": "int64", - "description": "제안서 ID", - "example": 1001 - }, - "isPartnered": { - "type": "boolean", - "description": "제휴 여부", - "example": true - }, - "status": { - "type": "string", - "description": "제휴 상태", - "example": "ACTIVE" - }, - "partnerId": { - "type": "integer", - "format": "int64", - "description": "제휴업체 ID", - "example": 201 - }, - "partnerName": { - "type": "string", - "description": "제휴업체 이름", - "example": "역전할머니맥주 숭실대점" - }, - "partnerAddress": { - "type": "string", - "description": "제휴업체 주소", - "example": "서울특별시 동작구 상도로" - } - } - }, - "BaseResponseAdminPartnershipCheckResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/AdminPartnershipCheckResponseDTO" - } - } - }, - "AdminLiteDTO": { - "type": "object", - "properties": { - "adminId": { - "type": "integer", - "format": "int64" - }, - "adminAddress": { - "type": "string" - }, - "adminDetailAddress": { - "type": "string" - }, - "adminName": { - "type": "string" - }, - "adminUrl": { - "type": "string" - }, - "adminPhone": { - "type": "string" - } - } - }, - "BaseResponsePartnerResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PartnerResponseDTO" - } - } - }, - "PartnerResponseDTO": { - "type": "object", - "properties": { - "admins": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AdminLiteDTO" - } - } - } - }, - "BaseResponseMapStringObject": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } - } - }, - "BaseResponseBoolean": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "boolean" - } - } - }, - "BaseResponseObject": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "object" - } - } - }, - "BaseResponseListPlaceSuggestionDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PlaceSuggestionDTO" - } - } - } - }, - "PlaceSuggestionDTO": { - "type": "object", - "properties": { - "placeId": { - "type": "string", - "description": "장소 ID", - "example": 12345678 - }, - "name": { - "type": "string", - "description": "장소 이름", - "example": "숭실대학교" - }, - "category": { - "type": "string", - "description": "장소 카테고리", - "example": "대학교" - }, - "address": { - "type": "string", - "description": "장소 지번 주소", - "example": "서울특별시 동작구 상도로 369" - }, - "roadAddress": { - "type": "string", - "description": "장소 도로명 주소", - "example": "서울특별시 동작구 상도로 369" - }, - "phone": { - "type": "string", - "description": "장소 전화번호", - "example": "02-820-0114" - }, - "placeUrl": { - "type": "string", - "description": "카카오맵 장소 Url", - "example": "https://place.map.kakao.com/12345678" - }, - "latitude": { - "type": "number", - "format": "double", - "description": "장소 위도", - "example": 37.5 - }, - "longitude": { - "type": "number", - "format": "double", - "description": "장소 경도", - "example": 126.96 - }, - "distance": { - "type": "integer", - "format": "int32", - "description": "현재 위치로부터의 거리 (m)", - "example": 100 - } - } - }, - "MapRequestDTO": { - "type": "object", - "properties": { - "lng1": { - "type": "number", - "format": "double", - "description": "화면 좌상단 경도", - "example": 126.95 - }, - "lat1": { - "type": "number", - "format": "double", - "description": "화면 좌상단 위도", - "example": 37.51 - }, - "lng2": { - "type": "number", - "format": "double", - "description": "화면 우상단 경도", - "example": 126.97 - }, - "lat2": { - "type": "number", - "format": "double", - "description": "화면 우상단 위도", - "example": 37.51 - }, - "lng3": { - "type": "number", - "format": "double", - "description": "화면 우하단 경도", - "example": 126.97 - }, - "lat3": { - "type": "number", - "format": "double", - "description": "화면 우하단 위도", - "example": 37.49 - }, - "lng4": { - "type": "number", - "format": "double", - "description": "화면 좌하단 경도", - "example": 126.95 - }, - "lat4": { - "type": "number", - "format": "double", - "description": "화면 좌하단 위도", - "example": 37.49 - } - }, - "required": [ - "lat1", - "lat2", - "lat3", - "lat4", - "lng1", - "lng2", - "lng3", - "lng4" - ] - }, - "BaseResponsePageResponseDTOInquiryResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/PageResponseDTOInquiryResponseDTO" - } - } - }, - "InquiryResponseDTO": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64", - "description": "문의 ID", - "example": 12 - }, - "title": { - "type": "string", - "description": "문의 제목", - "example": "상호명 변경 요청드립니다." - }, - "content": { - "type": "string", - "description": "문의 내용", - "example": "안녕하세요. 역할맥입니다. 상호명을 변경하고 싶습니다." - }, - "email": { - "type": "string", - "description": "문의자 이메일", - "example": "assu@gmail.com" - }, - "status": { - "type": "string", - "description": "문의 상태", - "example": "WAITING, ANSWERED, ALL" - }, - "answer": { - "type": "string", - "description": "답변 내용", - "example": "안녕하세요. A:SSU 팀입니다." - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "문의 생성 일시", - "example": "2026-01-20T14:30:00" - } - } - }, - "PageResponseDTOInquiryResponseDTO": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/InquiryResponseDTO" - } - }, - "page": { - "type": "integer", - "format": "int32" - }, - "size": { - "type": "integer", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "format": "int32" - }, - "totalElements": { - "type": "integer", - "format": "int64" - } - } - }, - "BaseResponseInquiryResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/InquiryResponseDTO" - } - } - }, - "BaseResponseListChatRoomListResultDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ChatRoomListResultDTO" - } - } - } - }, - "ChatRoomListResultDTO": { - "type": "object", - "properties": { - "roomId": { - "type": "integer", - "format": "int64" - }, - "lastMessage": { - "type": "string" - }, - "lastMessageTime": { - "type": "string", - "format": "date-time" - }, - "unreadMessagesCount": { - "type": "integer", - "format": "int64" - }, - "opponentId": { - "type": "integer", - "format": "int64" - }, - "opponentName": { - "type": "string" - }, - "opponentProfileImage": { - "type": "string" - }, - "phoneNumber": { - "type": "string" - } - } - }, - "BaseResponseChatHistoryResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/ChatHistoryResponseDTO" - } - } - }, - "ChatHistoryResponseDTO": { - "type": "object", - "properties": { - "roomId": { - "type": "integer", - "format": "int64" - }, - "messages": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ChatMessageDTO" - } - } - } - }, - "ChatMessageDTO": { - "type": "object", - "properties": { - "messageId": { - "type": "integer", - "format": "int64" - }, - "message": { - "type": "string" - }, - "sendTime": { - "type": "string", - "format": "date-time" - }, - "unreadCountForSender": { - "type": "integer", - "format": "int32" - }, - "isRead": { - "type": "boolean" - }, - "isMyMessage": { - "type": "boolean" - }, - "messageType": { - "type": "string", - "enum": [ - "TEXT", - "PROPOSAL", - "SYSTEM", - "GUIDE" - ] - } - } - }, - "BaseResponseCheckBlockMemberDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CheckBlockMemberDTO" - } - } - }, - "CheckBlockMemberDTO": { - "type": "object", - "properties": { - "memberId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string" - }, - "blocked": { - "type": "boolean" - } - } - }, - "BaseResponseListBlockMemberDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BlockMemberDTO" - } - } - } - }, - "AdminResponseDTO": { - "type": "object", - "properties": { - "partnerId": { - "type": "integer", - "format": "int64", - "description": "제휴업체 ID", - "example": 101 - }, - "partnerName": { - "type": "string", - "description": "제휴업체 이름", - "example": "역전할머니 맥주 숭실대점" - }, - "partnerAddress": { - "type": "string", - "description": "제휴업체 주소", - "example": "서울특별시 동작구" - }, - "partnerDetailAddress": { - "type": "string", - "description": "제휴업체 상세주소", - "example": "2층 201호" - }, - "partnerUrl": { - "type": "string", - "description": "제휴업체 URL", - "example": "https://www.beer.co.kr" - }, - "partnerPhone": { - "type": "string", - "description": "제휴업체 전화번호", - "example": "02-123-4567" - } - }, - "required": [ - "partnerAddress", - "partnerId", - "partnerName" - ] - }, - "BaseResponseAdminResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/AdminResponseDTO" - } - } - }, - "BaseResponseCountAdminAuthResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CountAdminAuthResponseDTO" - } - } - }, - "CountAdminAuthResponseDTO": { - "type": "object", - "properties": { - "studentCount": { - "type": "integer", - "format": "int64" - }, - "adminId": { - "type": "integer", - "format": "int64" - }, - "adminName": { - "type": "string" - } - } - }, - "BaseResponseCountUsageListResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CountUsageListResponseDTO" - } - } - }, - "CountUsageListResponseDTO": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CountUsageResponseDTO" - } - } - } - }, - "CountUsageResponseDTO": { - "type": "object", - "properties": { - "usageCount": { - "type": "integer", - "format": "int64" - }, - "adminId": { - "type": "integer", - "format": "int64" - }, - "adminName": { - "type": "string" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "storeName": { - "type": "string" - } - } - }, - "BaseResponseCountUsageResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CountUsageResponseDTO" - } - } - }, - "BaseResponseNewCountAdminResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/NewCountAdminResponseDTO" - } - } - }, - "NewCountAdminResponseDTO": { - "type": "object", - "properties": { - "newStudentCount": { - "type": "integer", - "format": "int64" - }, - "adminId": { - "type": "integer", - "format": "int64" - }, - "adminName": { - "type": "string" - } - } - }, - "BaseResponseCountUsagePersonResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/CountUsagePersonResponseDTO" - } - } - }, - "CountUsagePersonResponseDTO": { - "type": "object", - "properties": { - "usagePersonCount": { - "type": "integer", - "format": "int64" - }, - "adminId": { - "type": "integer", - "format": "int64" - }, - "adminName": { - "type": "string" - } - } - }, - "BaseResponseDeleteReviewResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/DeleteReviewResponseDTO" - } - } - }, - "DeleteReviewResponseDTO": { - "type": "object", - "properties": { - "reviewId": { - "type": "integer", - "format": "int64" - } - } - }, - "BaseResponseLeaveChattingRoomResponseDTO": { - "type": "object", - "properties": { - "isSuccess": { - "type": "boolean" - }, - "code": { - "type": "string" - }, - "message": { - "type": "string" - }, - "result": { - "$ref": "#/components/schemas/LeaveChattingRoomResponseDTO" - } - } - }, - "LeaveChattingRoomResponseDTO": { - "type": "object", - "properties": { - "roomId": { - "type": "integer", - "format": "int64" - }, - "isLeftSuccessfully": { - "type": "boolean" - }, - "isRoomDeleted": { - "type": "boolean" - } - } - } - }, - "securitySchemes": { - "JWT TOKEN": { - "type": "http", - "name": "JWT TOKEN", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - } -} \ No newline at end of file + "openapi": "3.1.0", + "info": { + "title": "ASSU API", + "description": "ASSU API 명세서", + "version": "1.0.0" + }, + "servers": [ + { + "url": "/" + } + ], + "security": [ + { + "JWT TOKEN": [] + } + ], + "tags": [ + { + "name": "Map", + "description": "지도 API" + }, + { + "name": "Review", + "description": "리뷰 API" + }, + { + "name": "Certification", + "description": "QR인증 API" + }, + { + "name": "Auth", + "description": "인증/인가 API" + }, + { + "name": "Report", + "description": "신고 API" + }, + { + "name": "Device Token", + "description": "디바이스 토큰 API" + }, + { + "name": "Admin", + "description": "관리자 API" + }, + { + "name": "Inquiry", + "description": "문의 API" + }, + { + "name": "App Review", + "description": "앱 리뷰 API" + }, + { + "name": "Store", + "description": "가게 API" + }, + { + "name": "Suggestion", + "description": "제휴 건의 API" + }, + { + "name": "Chatting", + "description": "채팅 API" + }, + { + "name": "Admin Dashboard", + "description": "관리자 대시보드 및 통계 API" + }, + { + "name": "Member", + "description": "멤버 API" + }, + { + "name": "Partner", + "description": "제휴업체 API" + }, + { + "name": "Student", + "description": "학생 API" + }, + { + "name": "Notification", + "description": "알림 API" + }, + { + "name": "Partnership", + "description": "제휴 제안 API" + }, + { + "name": "Temp QR", + "description": "임시 QR 인증 API" + } + ], + "paths": { + "/notifications/{type}": { + "put": { + "tags": ["Notification"], + "summary": "알림 유형별 ON/OFF 토글 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/on-off-2511197c19ed80aeb4eed3c502691361?source=copy_link)\n- 토글 형식으로 유형별 알림을 ON/OFF 합니다.\n- 그룹 토글 기능을 지원합니다.\n\n**Path Variable:**\n- `type` (NotificationType, required): 알림 유형\n - 개별 유형: CHAT, PARTNER_SUGGESTION, PARTNER_PROPOSAL, ORDER, STAMP\n - 그룹 유형: PARTNER_ALL (CHAT + ORDER), ADMIN_ALL (CHAT + PARTNER_SUGGESTION + PARTNER_PROPOSAL)\n\n**Response:**\n- 성공 시 200(OK)와 변경된 알림 설정 상태 반환\n- 400(BAD_REQUEST): 지원하지 않는 알림 유형\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", + "operationId": "toggle", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "CHAT", + "PARTNER_SUGGESTION", + "PARTNER_PROPOSAL", + "ORDER", + "PARTNER_ALL", + "ADMIN_ALL", + "STAMP" + ] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseNotificationSettingsResponseDTO" + } + } + } + } + } + } + }, + "/members/me/profile-image": { + "get": { + "tags": ["Member"], + "summary": "프로필 이미지 조회 API", + "description": "# [v1.0 (2025-09-18)](https://clumsy-seeder-416.notion.site/2711197c19ed8039bbe2c48380c9f4c8?source=copy_link)\n- 로그인한 사용자의 프로필 이미지 presigned URL을 반환합니다.\n- 반환된 URL은 일정 시간 동안만 유효합니다.\n- 프로필 이미지가 없는 경우 null 반환\n\n**Response:**\n- 성공 시 200(OK)와 presigned URL 반환\n- URL 유효 시간: 10분\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 500(INTERNAL_SERVER_ERROR): S3 presigned URL 생성 실패", + "operationId": "getProfileImage", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseProfileImageResponseDTO" + } + } + } + } + } + }, + "put": { + "tags": ["Member"], + "summary": "프로필 이미지 업로드/교체 API", + "description": "# [v1.0 (2025-09-15)](https://clumsy-seeder-416.notion.site/26f1197c19ed8031bc50e3571e8ea18f?source=copy_link)\n- `multipart/form-data`로 프로필 이미지를 업로드합니다.\n- 기존 이미지가 있으면 S3에서 삭제 후 새 이미지로 교체합니다.\n\n**Request Parts:**\n- `image` (MultipartFile, required): 프로필 이미지 파일\n - 지원 형식: JPG, PNG, WEBP 등\n - 최대 파일 크기 제한 있음\n\n**Response:**\n- 성공 시 200(OK)와 업로드된 이미지 key 반환\n- 400(BAD_REQUEST): 지원하지 않는 파일 형식 또는 파일 크기 초과\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 500(INTERNAL_SERVER_ERROR): S3 업로드 실패", + "operationId": "uploadOrReplaceProfileImage", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "image": { + "type": "string", + "format": "binary", + "description": "프로필 이미지 파일 (jpg/png/webp 등)" + } + }, + "required": ["image"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseProfileImageResponseDTO" + } + } + } + } + } + }, + "delete": { + "tags": ["Member"], + "summary": "프로필 이미지 삭제 API", + "description": "# [v1.0 (2025-09-18)](https://clumsy-seeder-416.notion.site/2dc1197c19ed809cb813f74a1b4c5c26?source=copy_link)\n- 로그인한 사용자의 프로필 이미지를 삭제합니다.\n- S3에서 이미지 파일을 완전히 삭제합니다.\n- 삭제 후 프론트에서 기본 이미지를 표시합니다.\n\n**Response:**\n- 성공 시 200(OK)와 성공 메시지 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 404(NOT_FOUND): 삭제할 프로필 이미지가 없음\n- 500(INTERNAL_SERVER_ERROR): S3 삭제 실패", + "operationId": "deleteProfileImage", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseString" + } + } + } + } + } + } + }, + "/temporary-qr/data": { + "post": { + "tags": ["Temp QR"], + "summary": "QR 데이터 삽입 API", + "description": "# # [v1.0 (2026-02-14)](https://clumsy-seeder-416.notion.site/QR-3071197c19ed8079aeb9d0555b9e899f?source=copy_link)\n- 임시 QR 적립 데이터를 저장합니다.\n- 요청 바디(JSON)를 통해 QR 적립 대상 정보를 전달합니다.\n\n**Request Body:**\n - `adminName` (String, required): 학생회(관리자) 이름 (ex. 컴퓨터학부 학생회, 총학생회, IT대 학생회)\n - `sort` (Enum, required): 어떻게 적립되었는지 REVIEW/SUGGEST 중 하나 입력\n\n**Response:**\n - 성공 시 200(OK)\n", + "operationId": "insertQrData", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemporaryQrRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/suggestion": { + "post": { + "tags": ["Suggestion"], + "summary": "제휴 건의 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-2241197c19ed81e68840d565af59b534)\n- 현재 로그인한 학생이 관리자에게 제휴를 건의합니다.\n- 성공 시 200(OK)과 Suggestion 객체 반환.\n\n**Request Body:**\n - `suggestionRequest` 객체 (JSON, required)\n - `adminId` (Long): 건의 대상 관리자 ID\n - `storeName` (String): 희망 가게 이름\n - `benefit` (String): 희망 혜택\n\n**Response:**\n - `suggestionId` (Long): 건의 ID\n - `userId` (Long): 제안인 ID\n - `adminId` (Long): 건의 대상 관리자 ID\n - `storeName` (String): 희망 가게 이름\n - `suggestionBenefit` (String): 희망 혜택\n", + "operationId": "writeSuggestion", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WriteSuggestionRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseWriteSuggestionResponseDTO" + } + } + } + } + } + } + }, + "/students/sync/all": { + "post": { + "tags": ["Student"], + "summary": "전체 학생의 사용 가능 제휴 동기화 API", + "description": "# [v1.0 (2026-03-16)](https://clumsy-seeder-416.notion.site/3251197c19ed8066885cece9ffc455f6?source=copy_link)\n- 모든 학생의 user_paper 데이터를 동기화합니다.\n- 관리자 전용 API입니다.\n- 시스템 전체에 영향을 주는 작업이므로 주의해서 사용해야 합니다.\n\n**주의사항:**\n- 대량의 데이터 처리로 인해 시간이 오래 걸릴 수 있음\n- 실행 중에는 다른 제휴 관련 작업에 영향을 줄 수 있음\n\n**Response:**\n- 성공 시 200(OK)와 동기화 완료 메시지 반환\n- 403(FORBIDDEN): 관리자 권한 없음\n- 500(INTERNAL_SERVER_ERROR): 동기화 작업 실패", + "operationId": "syncAllStudentsNow", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseString" + } + } + } + } + } + } + }, + "/students/stamp": { + "get": { + "tags": ["Student"], + "summary": "사용자 스탬프 개수 조회 API", + "description": "# [v1.0 (2025-09-09)](https://www.notion.so/2691197c19ed805c980dd546adee9301?source=copy_link)\n- `multipart/form-data`로 호출합니다.\n- login 필요 \n**Response:**\n - stamp 개수 반환 \n", + "operationId": "getStamp", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCheckStampResponseDTO" + } + } + } + } + } + }, + "post": { + "tags": ["Student"], + "summary": "스탬프 적립 및 이벤트 응모 API", + "description": "# [v1.0 (2026-02-23)](https://clumsy-seeder-416.notion.site/3101197c19ed80b5b47eceb202535469)\n- 스탬프가 10개가 되는 시점에 자동으로 응모및 알림", + "operationId": "earnStamp", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseString" + } + } + } + } + } + } + }, + "/reviews": { + "post": { + "tags": ["Review"], + "summary": "리뷰 작성 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2241197c19ed8176ba4fcb49c0136f93)\n- 리뷰 내용, 별점, 이미지를 멀티파트로 입력받아 저장합니다.\n- Authentication: JWT 토큰 필요 (Student 권한)", + "operationId": "writeReview", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "request": { + "$ref": "#/components/schemas/WriteReviewRequestDTO" + }, + "reviewImages": { + "type": "array", + "items": { + "type": "string", + "format": "binary" + } + } + }, + "required": ["request"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseWriteReviewResponseDTO" + } + } + } + } + } + } + }, + "/reports": { + "post": { + "tags": ["Report"], + "summary": "콘텐츠 신고 API", + "description": "# [v1.0 (2025-09-24)](https://clumsy-seeder-416.notion.site/API-2771197c19ed80b79afbf3d8d8d82c15?source=copy_link)\n- 신고자는 본인 Member ID로 자동 설정됩니다.\n- 자기 자신의 콘텐츠를 신고할 수 없습니다.\n- 동일한 대상을 중복 신고할 수 없습니다.\n\n**Request Body:**\n- `targetType` (ReportTargetType enum, required): 신고 대상 타입 (REVIEW, SUGGESTION)\n- `targetId` (Long, required): 리뷰 ID 또는 건의글 ID\n- `reportType` (ReportType enum, required): 신고 유형\n - 리뷰 신고: REVIEW_INAPPROPRIATE_CONTENT, REVIEW_FALSE_INFORMATION, REVIEW_SPAM\n - 건의글 신고: SUGGESTION_INAPPROPRIATE_CONTENT, SUGGESTION_FALSE_INFORMATION, SUGGESTION_SPAM\n\n**Response:**\n- 성공 시 201(CREATED)과 신고 ID 반환", + "operationId": "reportContent", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateContentReportRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCreateReportResponse" + } + } + } + } + } + } + }, + "/reports/students": { + "post": { + "tags": ["Report"], + "summary": "작성자 신고 API", + "description": "# [v1.0 (2025-09-24)](https://clumsy-seeder-416.notion.site/API-2771197c19ed80f8ab45e70772fcfc58?source=copy_link)\n- 신고자는 본인 Member ID로 자동 설정됩니다.\n- 자기 자신을 신고할 수 없습니다.\n- 동일한 작성자를 중복 신고할 수 없습니다.\n\n**Request Body:**\n- `targetType` (ReportTargetType enum, required): 신고 대상 타입 (REVIEW, SUGGESTION)\n- `targetId` (Long, required): 리뷰 ID 또는 건의글 ID\n- `reportType` (ReportType enum, required): 신고 유형\n - 사용자 신고: STUDENT_USER_SPAM, STUDENT_USER_INAPPROPRIATE_CONTENT, STUDENT_USER_HARASSMENT, STUDENT_USER_FRAUD, STUDENT_USER_PRIVACY_VIOLATION, STUDENT_USER_OTHER\n\n**Response:**\n- 성공 시 201(CREATED)과 신고 ID 반환", + "operationId": "reportStudent", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateStudentReportRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCreateReportResponse" + } + } + } + } + } + } + }, + "/partnership/usage": { + "post": { + "tags": ["Partnership"], + "summary": "제휴 사용내역 기록 API", + "description": "# [v1.0 (2025-12-23)](https://clumsy-seeder-416.notion.site/2681197c19ed8052804eddd5a1f3ce96?source=copy_link)\n- 제휴 제공 화면 전에 호출되어 유저의 제휴 내역에 데이터를 기록합니다.\n- 인증 이후 제휴를 받았다는 때 서버의 데이터 기록을 요청하는 API \n- 개인 인증 케이스도 포함됩니다.\n\n**Request Body:**\n - `storeId` (Long, required): 제휴 매장 ID\n - `tableNumber` (String, required): 테이블 번호\n - `adminName` (String, required): 관리자 이름\n - `placeName` (String, required): 제휴 장소 이름\n - `partnershipContent` (String, required): 제휴 내용\n - `contentId` (Long, required): 제휴 컨텐츠 ID\n - `discount` (Long, optional): 할인 금액\n - `userIds` (List, optional): 인증 대상 유저 ID 목록\n\n**Response:**\n - 성공: 200 OK, `isSuccess=true`, `result=null`\n - 실패: 적절한 에러 코드 및 메시지", + "operationId": "finalPartnershipRequest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PartnershipFinalRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/partnership/proposal/draft": { + "post": { + "tags": ["Partnership"], + "summary": "제휴 제안서 초안 생성 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed8043a511cc8ea005d5b4)\n- 관리자로 로그인한 상태에서 제안서 초안을 생성합니다.\n- 제안서를 작성할 제휴업체 ID 입력.\n\n**Request Body:**\n - `CreateDraftRequest` 객체 (JSON, required)\n - `partnerId` (Long): 제휴 제안서를 작성할 제휴업체 ID\n\n**Response:**\n - 성공 시 200(OK)과 `CreateDraftResponse` 객체 반환.\n - `paperId` (Long): 생성된 제안서 ID\n", + "operationId": "createDraftPartnership", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PartnershipDraftRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePartnershipDraftResponseDTO" + } + } + } + } + } + } + }, + "/partnership/passivity": { + "post": { + "tags": ["Partnership"], + "summary": "제휴 제안서 수동 등록 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed804785d9f58f95223048)\n- 관리자로 로그인한 상황에서 내용이 있는 제휴 제안서를 생성합니다.\n- 계약서 이미지 MultipartFile을 입력.\n- 주소 입력 시 장소 검색용 API에서 반환된 Map 객체의 내용을 selectedPlace에 입력.\n- options의 optionType을 SERVICE/DISCOUNT 중 하나로 설정.\n- options의 criterionType을 PRICE/HEADCOUNT 중 하나로 설정.\n- 이외의 제휴 유형일 경우 anotherType을 true로 설정.\n- DB에 해당하는 store가 없다면 생성.\n- 해당하는 store가 INACTIVE 상태였다면 ACTIVE 상태로 변환.\n\n**Request Body:**\n - `ManualPartnershipRequest` 객체 (JSON, required): 제안서 내용\n - `storeName` (String): 가게 이름\n - `selectedPlace` (JSON): 선택된 장소\n - `placeId` (String): kakao place ID\n - `name` (String): kakao place 이름\n - `address` (String): 지번 주소\n - `roadAddress` (String): 도로명 주소\n - `latitude` (Double): 장소 위도\n - `longitude` (Double): 장소 경도\n - `storeDetailAddress` (String): 가게 상세주소\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `goods` (JSON): 서비스 제공 항목\n - `goodsName` (String): 서비스 제공 항목명\n - `contractImage` (MultipartFile, required): 계약서 이미지 파일\n\n**Response:**\n - 성공 시 200(OK)과 `ManualPartnershipResponse` 객체 반환.\n - `storeId` (Long): 가게 ID\n - `storeCreated` (boolean): 가게가 DB에 생성되었는지 여부\n - `storeActivated` (boolean): 가게가 재활성화되었는지 여부\n - `status` (String): 제휴 제안서의 상태\n - `contractImageUrl` (String): 계약서 파일 URL\n - `partnership` (JSON): 제휴 제안서\n - `partnershipId` (Long): 제안서 ID\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `storeName` (String): 가게 이름\n - `adminName` (String): 관리자 이름\n - `isActivated` (ActivationStatus): 제안서 활성화 여부\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", + "operationId": "createManualPartnership", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "request": { + "$ref": "#/components/schemas/ManualPartnershipRequestDTO" + }, + "contractImage": { + "type": "string", + "format": "binary", + "description": "계약서 이미지 파일" + } + }, + "required": ["contractImage", "request"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseManualPartnershipResponseDTO" + } + } + } + } + } + } + }, + "/notifications/{notificationId}/read": { + "post": { + "tags": ["Notification"], + "summary": "알림 읽음 처리 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2491197c19ed80a89ff0c03bc150460f?source=copy_link)\n- 알림 ID에 해당하는 알림을 읽음 처리합니다.\n- 본인의 알림만 읽음 처리 가능합니다.\n\n**Path Variable:**\n- `notificationId` (Long, required): 알림 ID\n\n**Response:**\n- 성공 시 200(OK)과 성공 메시지 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 403(FORBIDDEN): 다른 사용자의 알림 접근 시도\n- 404(NOT_FOUND): 존재하지 않는 알림 ID\n- 409(CONFLICT): 이미 읽음 처리된 알림", + "operationId": "markRead", + "parameters": [ + { + "name": "notificationId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseString" + } + } + } + } + } + } + }, + "/notifications/queue": { + "post": { + "tags": ["Notification"], + "summary": "알림 전송 테스트 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2511197c19ed8051bc93d95f0b216543?source=copy_link)\n- 알림 전송 기능을 테스트합니다.\n- 디바이스 토큰을 등록한 이후에 사용 가능합니다.\n\n**Request Body:**\n- `memberId` (Long, required): 대상 멤버 ID\n- `title` (String, required): 알림 제목\n- `body` (String, required): 알림 내용\n\n**Response:**\n- 성공 시 200(OK)과 성공 메시지 반환\n- 400(BAD_REQUEST): 필수 필드 누락\n- 404(NOT_FOUND): 존재하지 않는 멤버 ID 또는 디바이스 토큰 없음\n- 500(INTERNAL_SERVER_ERROR): FCM 전송 실패", + "operationId": "queue", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueueNotificationRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseString" + } + } + } + } + } + } + }, + "/inquiries": { + "get": { + "tags": ["Inquiry"], + "summary": "문의 내역 목록 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2441197c19ed803eba4af9598484e5c5?source=copy_link)\n- 본인의 문의 내역 목록을 상태별로 조회합니다.\n\n**Request Parameters:**\n- `status` (String, optional): 문의 상태 (WAITING, ANSWERED, ALL) - 기본값: ALL\n- `page` (Integer, optional): 페이지 번호 (1 이상) - 기본값: 1\n- `size` (Integer, optional): 페이지 크기 - 기본값: 20\n\n**Response:**\n- 성공 시 200(OK)과 문의 목록 반환\n- 400(BAD_REQUEST): 잘못된 페이지 번호 또는 상태 값\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", + "operationId": "list", + "parameters": [ + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "ALL", + "enum": ["WAITING", "ANSWERED", "ALL"] + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 1, + "minimum": 1 + } + }, + { + "name": "size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 20 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePageResponseDTOInquiryResponseDTO" + } + } + } + } + } + }, + "post": { + "tags": ["Inquiry"], + "summary": "문의하기 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2441197c19ed800688f0cfb304dead63?source=copy_link)\n- 문의를 생성하고 해당 문의의 ID를 반환합니다.\n\n**Request Body:**\n- `title` (String, required): 문의 제목\n- `content` (String, required): 문의 내용\n- `email` (String, required): 답변 받을 이메일\n\n**Response:**\n- 성공 시 200(OK)과 생성된 문의 ID 반환\n- 400(BAD_REQUEST): 필수 필드 누락 또는 잘못된 이메일 형식\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", + "operationId": "create", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InquiryCreateRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLong" + } + } + } + } + } + } + }, + "/device-tokens": { + "post": { + "tags": ["Device Token"], + "summary": "디바이스 토큰 등록 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed8092864ac5a1ddc88d07?source=copy_link)\n- 디바이스 토큰을 등록하고 등록된 토큰의 ID를 반환합니다.\n- 푸시 알림 수신을 위해 필수로 등록해야 합니다.\n\n**Request Parameters:**\n- `token` (String, required): FCM 디바이스 토큰\n\n**Response:**\n- 성공 시 200(OK)과 등록된 토큰 ID 반환\n- 400(BAD_REQUEST): 빈 토큰 또는 잘못된 토큰 형식\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 409(CONFLICT): 이미 등록된 토큰", + "operationId": "register", + "parameters": [ + { + "name": "token", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLong" + } + } + } + } + } + } + }, + "/chat/rooms": { + "get": { + "tags": ["Chatting"], + "summary": "채팅방 목록 조회 API", + "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/API-1d71197c19ed819f8f70fb437e9ce62b?p=2241197c19ed816993c3c5ae17d6f099&pm=s)\n- 채팅방 목록을 조회합니다.\n", + "operationId": "getChatRoomList", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListChatRoomListResultDTO" + } + } + } + } + } + }, + "post": { + "tags": ["Chatting"], + "summary": "채팅방 생성 API", + "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed80c38871ec77deced713)\n- 채팅방을 생성합니다.\n\n**Request Body:**\n- adminId (Long, required): 관리자 ID\n- partnerId (Long, required) 제휴업체 ID\n", + "operationId": "createChatRoom", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateChatRoomRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCreateChatRoomResponseDTO" + } + } + } + } + } + } + }, + "/chat/block": { + "post": { + "tags": ["Chatting"], + "summary": "상대방 차단 API", + "description": "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed804ba3dbf57ba36860c4)\n- 상대방을 차단합니다.\n- 메시지를 주고받을 수 없습니다.\n\n**Request Body:**\n- opponentId (Long, required): 상대방 ID\n", + "operationId": "block", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlockMemberRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBlockMemberDTO" + } + } + } + } + } + } + }, + "/certification/session": { + "post": { + "tags": ["Certification"], + "summary": "세션 정보 요청 API", + "description": "# [v1.0 (2025-09-09)](https://www.notion.so/22b1197c19ed80bb8484d99cc6ce715b?source=copy_link)\n- `multipart/form-data`로 호출합니다.\n- 파트: `payload`(JSON, CertificationRequest.groupRequest)\n- 처리: 정보 바탕으로 sessionManager에 session생성\n- 성공 시 201(Created)과 생성된 memberId 반환.\n\n**Request Parts:**\n - `request` (JSON, required): `CertificationRequest.groupRequest` 객체\n - `people` (Integer, required): 인증이 필요한 인원\n - `storeId` (Long, required): 스토어 id\n - `adminId` (Long, required): 관리자 id\n - `tableNumber` (Integer, required): 테이블 넘버\n\n**Response:**\n - 성공 시 201(Created)와 sessionId, adminId 반환", + "operationId": "getSessionId", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CertificationGroupRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCertificationResponseDTO" + } + } + } + } + } + } + }, + "/certification/personal": { + "post": { + "tags": ["Certification"], + "summary": "개인 인증 요청 API", + "description": "# [v1.0 (2025-09-09)](https://clumsy-seeder-416.notion.site/2471197c19ed80fd9a8dcc43fb938a5d?source=copy_link)\n- 개인 단위 인증을 위한 API입니다.\n- 그룹 인증이 아닌 경우, 통계 및 제휴 이력 적재를 목적으로 사용됩니다.\n- 가게별 제휴 조회 시 `people` 값이 null 인 경우 호출됩니다.\n\n**Request Body:**\n - `storeId` (Long, required): 인증이 발생한 스토어 ID\n - `adminId` (Long, required): 인증을 요청한 관리자 ID\n - `tableNumber` (Integer, required): 인증이 발생한 테이블 번호\n\n**Authentication:**\n - 로그인된 사용자 인증 정보 필요 (`@AuthenticationPrincipal`)\n\n**Processing:**\n - 전달받은 정보 기반으로 개인 인증 이력 저장\n - 세션 생성은 하지 않음\n\n**Response:**\n - 성공 시 200(OK)\n - 성공 메시지 반환", + "operationId": "personalCertification", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CertificationPersonalRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseString" + } + } + } + } + } + } + }, + "/auth/tokens/refresh": { + "post": { + "tags": ["Auth"], + "summary": "Access Token 갱신 API", + "description": "# [v1.0 (2025-09-03)](https://clumsy-seeder-416.notion.site/2501197c19ed806ea8cff29f9cd8695a?source=copy_link)\n- 헤더로 호출합니다.\n- 헤더: `RefreshToken: `.\n- 처리: Refresh 검증/회전 후 신규 Access/Refresh 발급 및 저장.\n- 성공 시 200(OK)과 신규 토큰 반환.\n\n**Headers:**\n - `RefreshToken` (String, required): 리프레시 토큰\n\n**Response:**\n - 성공 시 200(OK)과 `RefreshResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `newAccess` (String): 새로운 액세스 토큰\n - `newRefresh` (String): 새로운 리프레시 토큰", + "operationId": "refreshToken", + "parameters": [ + { + "name": "RefreshToken", + "in": "header", + "description": "Refresh Token", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseRefreshResponseDTO" + } + } + } + } + } + } + }, + "/auth/students/ssu-verify": { + "post": { + "tags": ["Auth"], + "summary": "숭실대 유세인트 인증 API", + "description": "# [v1.0 (2025-09-03)](https://clumsy-seeder-416.notion.site/23a1197c19ed808d9266e641e5c4ea14?source=copy_link)\n- `application/json`으로 호출합니다.\n\n**Request Body:**\n - `sToken` (String, required): 유세인트 sToken\n - `sIdno` (String, required): 유세인트 sIdno\n- 처리 순서:\n 1) 유세인트 SSO 로그인 시도 (sToken, sIdno 검증)\n 2) 응답 Body 검증 후 세션 쿠키 추출\n 3) 유세인트 포털 페이지 접근 및 HTML 파싱\n 4) 이름, 학번, 소속, 학적 상태, 학년/학기 정보 추출\n 5) 소속 문자열을 전공 Enum(`Major`)으로 매핑\n 6) 인증 결과를 `USaintAuthResponseDTO`로 반환\n\n**Response:**\n - 성공 시 200(OK)과 `USaintAuthResponseDTO` 객체 반환\n - `studentNumber` (String): 학번\n - `name` (String): 이름\n - `enrollmentStatus` (String): 학적 상태\n - `yearSemester` (String): 학년/학기\n - `major` (Major enum): 전공/학과", + "operationId": "ssuAuth", + "requestBody": { + "description": "유세인트 인증 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/USaintAuthRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseUSaintAuthResponseDTO" + } + } + } + } + } + } + }, + "/auth/students/signup": { + "post": { + "tags": ["Auth"], + "summary": "학생 회원가입 API", + "description": "# [v1.3 (2026-04-02)](https://clumsy-seeder-416.notion.site/2241197c19ed81129c85cf5bbe1f7971)\n- `application/json` 요청 바디를 사용합니다.\n- 처리: 유세인트 인증 → 학생 정보 추출 → 회원가입 완료\n- 성공 시 200(OK)과 생성된 memberId, JWT 토큰, 기본 정보 반환.\n\n**Request Body:**\n - `StudentTokenSignUpRequestDTO` 객체 (JSON, required): 숭실대 학생 토큰 가입 정보\n - `marketingAgree` (Boolean, required): 마케팅 수신 동의\n - `locationAgree` (Boolean, required): 위치 정보 수집 동의\n - `studentTokenAuth` (StudentTokenAuthPayloadDTO, Object, required): 유세인트 토큰 정보\n - `sToken` (String, required): 유세인트 sToken\n - `sIdno` (String, required): 유세인트 sIdno\n - `university` (University enum, required): 대학 이름 (SSU)\n\n**Response:**\n - 성공 시 200(OK)과 `SignUpResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (STUDENT)\n - `status` (ActivationStatus): 회원 상태 (ACTIVE)\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 학생 이름\n - `university` (String): 대학교 (한글명)\n - `department` (String): 단과대 (한글명)\n - `major` (String): 전공/학과 (한글명)", + "operationId": "signupStudent", + "requestBody": { + "description": "JSON 형식의 학생 유저 가입 정보", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StudentTokenSignUpRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseSignUpResponseDTO" + } + } + } + } + } + } + }, + "/auth/students/login": { + "post": { + "tags": ["Auth"], + "summary": "학생 로그인 API", + "description": "# [v1.2 (2025-09-13)](https://clumsy-seeder-416.notion.site/2501197c19ed80f6b495fa37f8c084a8)\n- `application/json`로 호출합니다.\n- 바디: `StudentTokenAuthPayloadDTO(sToken, sIdno, university)`.\n- 처리: 유세인트 인증 → 기존 회원 확인 → JWT 토큰 발급.\n- 성공 시 200(OK)과 토큰(accessToken/refreshToken), 기본 정보 반환.\n\n**Request Body:**\n - `StudentTokenAuthPayloadDTO` 객체 (JSON, required): 숭실대 학생 토큰 로그인 정보\n - `sToken` (String, required): 유세인트 sToken\n - `sIdno` (String, required): 유세인트 sIdno\n - `university` (University enum, required): 대학 이름 (SSU)\n\n**Response:**\n - 성공 시 200(OK)과 `LoginResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (STUDENT)\n - `status` (ActivationStatus): 회원 상태\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 학생 이름\n - `university` (String): 대학교 (한글명)\n - `department` (String): 단과대 (한글명)\n - `major` (String): 전공/학과 (한글명)", + "operationId": "loginStudent", + "requestBody": { + "description": "학생 토큰 로그인 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StudentTokenAuthPayloadDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLoginResponseDTO" + } + } + } + } + } + } + }, + "/auth/phone-verification/verify": { + "post": { + "tags": ["Auth"], + "summary": "휴대폰 인증번호 검증 API", + "description": "# [v1.0 (2025-09-03)](https://clumsy-seeder-416.notion.site/2241197c19ed81bb8c05d9061c0306c0?source=copy_link)\n- 발송된 인증번호(OTP)를 검증합니다.\n\n**Request Body:**\n - `phoneNumber` (String, required): 인증받을 휴대폰 번호\n - `authNumber` (String, required): 발송받은 인증번호(OTP)\n\n**Response:**\n - 성공 시 200(OK)과 성공 메시지 반환", + "operationId": "checkAuthNumber", + "requestBody": { + "description": "휴대폰 인증번호 검증 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PhoneAuthVerifyRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/auth/phone-verification/check-and-send": { + "post": { + "tags": ["Auth"], + "summary": "휴대폰 번호 중복가입 확인 및 인증번호 발송 API", + "description": "# [v1.1 (2025-09-25)](https://clumsy-seeder-416.notion.site/2241197c19ed801bbcd9f61c3e5f5457?source=copy_link)\n- 입력한 휴대폰 번호로 1회용 인증번호(OTP)를 발송합니다.\n- 중복된 전화번호가 있으면 에러를 반환합니다.\n- 관리자와 제휴업체의 회원가입 이전에 사용하여 전화번호를 검증합니다.\n- 유효시간/재요청 제한 정책은 서버 설정에 따릅니다.\n\n**Request Body:**\n - `phoneNumber` (String, required): 인증번호를 받을 휴대폰 번호\n\n**Response:**\n - 성공 시 200(OK)과 성공 메시지 반환", + "operationId": "checkPhoneAvailabilityAndSendAuthNumber", + "requestBody": { + "description": "휴대폰 인증번호 발송 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PhoneAuthSendRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/auth/partners/signup": { + "post": { + "tags": ["Auth"], + "summary": "제휴업체 회원가입 API", + "description": "# [v1.2 (2025-09-13)](https://clumsy-seeder-416.notion.site/2501197c19ed80d7a8f2c3a6fcd8b537)\n- `multipart/form-data`로 호출합니다.\n- 파트: `request`(JSON, PartnerSignUpRequestDTO) + `licenseImage`(파일, 사업자등록증).\n- 처리: users + common_auth 생성, 이메일 중복/비밀번호 규칙 검증.\n- 성공 시 200(OK)과 생성된 memberId, JWT 토큰, 기본 정보 반환.\n\n**Request Parts:**\n - `request` (JSON, required): `PartnerSignUpRequestDTO` 객체\n - `phoneNumber` (String, required): 휴대폰 번호\n - `marketingAgree` (Boolean, required): 마케팅 수신 동의\n - `locationAgree` (Boolean, required): 위치 정보 수집 동의\n - `commonAuth` (CommonAuthPayloadDTO, required): 이메일/비밀번호 및 인증 관련 정보\n - `email` (String, required): 이메일 주소\n - `password` (String, required): 비밀번호(평문)\n - `university` (University enum, required): 대학교 Enum\n - `department` (Department enum, required): 단과대 Enum\n - `major` (Major enum, required): 전공 Enum\n - `commonInfo` (CommonInfoPayloadDTO, required): 사용자 기본 정보\n - `name` (String, required): 업체명\n - `detailAddress` (String, required): 상세 주소\n - `selectedPlace` (SelectedPlacePayload, required): 선택된 장소 정보\n - `placeId` (String, required): 장소 ID\n - `name` (String, required): 장소 이름\n - `address` (String, required): 장소 지번 주소\n - `roadAddress` (String, required): 장소 도로명 주소\n - `latitude` (Double, required): 장소 위도\n - `longitude` (Double, required): 장소 경도\n - `licenseImage` (MultipartFile, required): 사업자등록증 이미지 파일\n\n**Response:**\n - 성공 시 200(OK)과 `SignUpResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (PARTNER)\n - `status` (ActivationStatus): 회원 상태 (ACTIVE)\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 업체명\n - `university` (String): null (Partner는 해당 없음)\n - `department` (String): null (Partner는 해당 없음)\n - `major` (String): null (Partner는 해당 없음)", + "operationId": "signupPartner", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "request": { + "$ref": "#/components/schemas/PartnerSignUpRequestDTO" + }, + "licenseImage": { + "type": "string", + "format": "binary", + "description": "사업자등록증 이미지 파일" + } + }, + "required": ["licenseImage", "request"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseSignUpResponseDTO" + } + } + } + } + } + } + }, + "/auth/logout": { + "post": { + "tags": ["Auth"], + "summary": "로그아웃 API", + "description": "# [v1.0 (2025-09-03)](https://clumsy-seeder-416.notion.site/23a1197c19ed809e9a09fcd741f554c8?source=copy_link)\n- 헤더로 호출합니다.\n- 헤더: `Authorization: Bearer `.\n- 처리: Refresh 무효화(선택), Access 블랙리스트 등록.\n- 성공 시 200(OK).", + "operationId": "logout", + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "Access Token. 형식: `Bearer `", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/auth/email-verification/check": { + "post": { + "tags": ["Auth"], + "summary": "이메일 형식 및 중복가입 확인 API", + "description": "# [v1.0 (2025-09-18)](https://clumsy-seeder-416.notion.site/2551197c19ed802d8f6dd373dd045f3a?source=copy_link)\n- 입력한 이메일이 이미 가입된 사용자가 있는지 확인합니다.\n- 중복된 이메일이 있으면 에러를 반환합니다.\n\n**Request Body:**\n - `email` (String, required): 확인할 이메일 주소\n\n**Response:**\n - 성공 시 200(OK)과 사용 가능 메시지 반환\n - 중복 시 404(NOT_FOUND)와 에러 메시지 반환", + "operationId": "checkEmailAvailability", + "requestBody": { + "description": "이메일 중복 확인 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailVerificationCheckRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/auth/commons/login": { + "post": { + "tags": ["Auth"], + "summary": "공통 로그인 API", + "description": "# [v1.1 (2025-09-13)](https://clumsy-seeder-416.notion.site/2241197c19ed811c961be6a474de0e50)\n- `application/json`로 호출합니다.\n- 바디: `CommonLoginRequestDTO(email, password)`.\n- 처리: 자격 증명 검증 후 Access/Refresh 토큰 발급 및 저장.\n- 성공 시 200(OK)과 토큰(accessToken/refreshToken), 기본 정보 반환.\n\n**Request Body:**\n - `CommonLoginRequestDTO` 객체 (JSON, required): 로그인 정보\n - `email` (String, required): 이메일 주소\n - `password` (String, required): 비밀번호\n\n**Response:**\n - 성공 시 200(OK)과 `LoginResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (PARTNER/ADMIN)\n - `status` (ActivationStatus): 회원 상태\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 업체명/단체명/관리자 이름\n - `university` (String): Admin인 경우 한글명, Partner인 경우 null\n - `department` (String): Admin인 경우 한글명, Partner인 경우 null\n - `major` (String): Admin인 경우 한글명, Partner인 경우 null", + "operationId": "loginCommon", + "requestBody": { + "description": "공통 로그인 요청 (파트너/관리자)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CommonLoginRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLoginResponseDTO" + } + } + } + } + } + } + }, + "/auth/admins/signup": { + "post": { + "tags": ["Auth"], + "summary": "관리자 회원가입 API", + "description": "# [v1.2 (2025-09-13)](https://clumsy-seeder-416.notion.site/2501197c19ed80cdb98bc2b4d5042b48)\n- `multipart/form-data`로 호출합니다.\n- 파트: `request`(JSON, AdminSignUpRequestDTO) + `signImage`(파일, 신분증).\n- 처리: users + common_auth 생성, 이메일 중복/비밀번호 규칙 검증.\n- 성공 시 200(OK)과 생성된 memberId, JWT 토큰, 기본 정보 반환.\n\n**Request Parts:**\n - `request` (JSON, required): `AdminSignUpRequestDTO` 객체\n - `phoneNumber` (String, required): 휴대폰 번호\n - `marketingAgree` (Boolean, required): 마케팅 수신 동의\n - `locationAgree` (Boolean, required): 위치 정보 수집 동의\n - `commonAuth` (CommonAuthPayloadDTO, required): 이메일/비밀번호 및 인증 관련 정보\n - `email` (String, required): 이메일 주소\n - `password` (String, required): 비밀번호(평문)\n - `university` (University enum, required): 대학교 Enum\n - `department` (Department enum, required): 단과대 Enum\n - `major` (Major enum, required): 전공 Enum\n - `commonInfo` (CommonInfoPayloadDTO, required): 사용자 기본 정보\n - `name` (String, required): 단체명/관리자 이름\n - `detailAddress` (String, required): 상세 주소\n - `selectedPlace` (SelectedPlacePayload, required): 선택된 장소 정보\n - `placeId` (String, required): 장소 ID\n - `name` (String, required): 장소 이름\n - `address` (String, required): 장소 지번 주소\n - `roadAddress` (String, required): 장소 도로명 주소\n - `latitude` (Double, required): 장소 위도\n - `longitude` (Double, required): 장소 경도\n - `signImage` (MultipartFile, required): 인감 이미지 파일\n\n**Response:**\n - 성공 시 200(OK)과 `SignUpResponseDTO` 객체 반환\n - `memberId` (Long): 회원 ID\n - `role` (UserRole): 회원 역할 (ADMIN)\n - `status` (ActivationStatus): 회원 상태 (ACTIVE)\n - `tokens` (Object): JWT 토큰 정보 (accessToken, refreshToken)\n - `basicInfo` (UserBasicInfo): 사용자 기본 정보 (프론트 캐싱용)\n - `name` (String): 단체명/관리자 이름\n - `university` (String): 대학교 (한글명)\n - `department` (String): 단과대 (한글명)\n - `major` (String): 전공/학과 (한글명)", + "operationId": "signupAdmin", + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "request": { + "$ref": "#/components/schemas/AdminSignUpRequestDTO" + }, + "signImage": { + "type": "string", + "format": "binary", + "description": "인감 이미지 파일 (Multipart Part)" + } + }, + "required": ["request", "signImage"] + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseSignUpResponseDTO" + } + } + } + } + } + } + }, + "/app-reviews": { + "post": { + "tags": ["App Review"], + "summary": "앱 리뷰 작성 API", + "description": "# [v1.0 (2026-02-09)](https://clumsy-seeder-416.notion.site/3021197c19ed80cf9ce3e7b8d7401fad)\n- `application/json`로 호출합니다.\n- 바디: `AppReviewRequestDTO(rate, content)`.\n- 처리: 자격 증명 검증 후 앱 리뷰 생성 및 저장.\n- 성공 시 200(OK) 반환.\n\n**Request Body:**\n - `rate` (Integer, required): 별점 1~5\n - `content` (String, required): 후기 내용\n\n**Response:**\n - 성공 시 200(OK)과 성공 메시지 반환", + "operationId": "createAppReview", + "requestBody": { + "description": "앱 리뷰 작성 요청", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppReviewRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/partnership/{partnershipId}/status": { + "patch": { + "tags": ["Partnership"], + "summary": "제휴 상태 업데이트 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/SUSPEND-ACTIVE-INACTIVE-2371197c19ed805ab509f552817e823a)\n- 제휴 상태를 변경합니다.\n- 적용할 상태 입력 (ACTIVE/SUSPEND/INACTIVE).\n\n**Parameters:**\n - `partnershipId` (Long, required): 상태를 적용할 제안서 ID\n\n**Request Body:**\n - `UpdateRequest` 객체 (JSON, required)\n - `status` (String): 제안서에 적용할 상태\n\n**Response:**\n - 성공 시 200(OK)과 `UpdateResponse` 객체 반환.\n - `partnershipId` (Long): 생성된 제안서 ID\n - `prevStatus` (String): 제안서의 이전 상태\n - `newStatus` (String): 제안서의 이전 상태\n - `changedAt` (LocalDateTime): 상태 변경 시간\n", + "operationId": "updatePartnershipStatus", + "parameters": [ + { + "name": "partnershipId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PartnershipStatusUpdateRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePartnershipStatusUpdateResponseDTO" + } + } + } + } + } + } + }, + "/partnership/proposal": { + "patch": { + "tags": ["Partnership"], + "summary": "제휴 제안서 내용 수정 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2371197c19ed80aa8468d2377ef8eac2)\n- 제안서 초안 또는 이미 작성된 제안서의 내용을 수정합니다.\n- options의 optionType을 SERVICE/DISCOUNT 중 하나로 설정\n- options의 criterionType을 PRICE/HEADCOUNT 중 하나로 설정\n- 이외의 제휴 유형일 경우 anotherType을 true로 설정\n\n**Request Body:**\n - `WritePartnershipRequest` 객체 (JSON, required): 수정 내용\n - `paperId` (String): 이메일 주소\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `goods` (JSON): 서비스 제공 항목\n - `goodsName` (String): 서비스 제공 항목명\n\n**Response:**\n - 성공 시 200(OK)과 `WritePartnershipResponse` 객체 반환\n - `partnershipId` (Long): 제안서 ID\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `storeName` (String): 가게 이름\n - `adminName` (String): 관리자 이름\n - `isActivated` (ActivationStatus): 제안서 활성화 여부\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", + "operationId": "updatePartnership", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WritePartnershipRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseWritePartnershipResponseDTO" + } + } + } + } + } + } + }, + "/inquiries/{inquiryId}/answer": { + "patch": { + "tags": ["Inquiry"], + "summary": "운영자 답변 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed8064808fcca568b8912a?source=copy_link)\n- 문의에 답변을 저장하고 상태를 ANSWERED로 변경합니다.\n\n**Path Variable:**\n- `inquiryId` (Long, required): 문의 ID\n\n**Request Body:**\n- `answer` (String, required): 답변 내용\n\n**Response:**\n- 성공 시 200(OK)과 성공 메시지 반환\n- 400(BAD_REQUEST): 빈 답변 내용\n- 403(FORBIDDEN): 운영자 권한 없음\n- 404(NOT_FOUND): 존재하지 않는 문의 ID\n- 409(CONFLICT): 이미 답변된 문의", + "operationId": "answer", + "parameters": [ + { + "name": "inquiryId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InquiryAnswerRequestDTO" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseString" + } + } + } + } + } + } + }, + "/chat/rooms/{roomId}/read": { + "patch": { + "tags": ["Chatting"], + "summary": "메시지 읽음 처리 API", + "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed800eab45c35073761c97?v=2241197c19ed8134b64f000cc26c5d31&p=2241197c19ed81ffa771cb18ab157b54&pm=s)\n- 메시지를 읽음처리합니다.\n\n**Path Variable:**\n- roomId (Long, required): 채팅방 ID\n", + "operationId": "readMessage", + "parameters": [ + { + "name": "roomId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseReadMessageResponseDTO" + } + } + } + } + } + } + }, + "/auth/withdraw": { + "patch": { + "tags": ["Auth"], + "summary": "회원 탈퇴 API", + "description": "# [v1.0 (2025-09-13)](https://clumsy-seeder-416.notion.site/2501197c19ed800a844bdafa2e2e8d2e?source=copy_link)\n- 현재 로그인한 사용자의 회원 탈퇴를 처리합니다.\n- 소프트 삭제 방식으로, 한 달 후 완전히 삭제됩니다.\n- 탈퇴 즉시 모든 토큰이 무효화됩니다.\n\n**Headers:**\n - `Authorization` (String, required): Bearer 토큰 형식의 액세스 토큰\n\n**Response:**\n - 성공 시 200(OK)과 성공 메시지 반환\n - 탈퇴 후 재로그인 가능", + "operationId": "withdrawMember", + "parameters": [ + { + "name": "Authorization", + "in": "header", + "description": "Access Token. 형식: `Bearer `", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/temporary-qr/mydata": { + "get": { + "tags": ["Temp QR"], + "summary": "내 QR 적립 데이터 조회 API", + "description": "# # [v1.0 (2026-02-15)](https://clumsy-seeder-416.notion.site/QR-3081197c19ed805e9f6bd012dafe6f01?source=copy_link)\n- 로그인한 사용자의 임시 QR 적립 데이터를 조회합니다.\n- 인증된 사용자의 토큰을 통해 자동으로 데이터를 가져옵니다.\n\n**Request:**\n - 별도의 파라미터 없음 (토큰 기반 인증)\n\n**Response:**\n - `adminName` (String): 학생회(관리자) 이름- 만약 앱 리뷰인 경우 \"\" 와 같이 들어가게 됨\n - `sort` (Enum): 적립 방식 (REVIEW/SUGGEST)\n - `createdAt` (String): 적립 일시\n\n**Response Example:**\n```json\n[\n {\n \"adminName\": \"총학생회\",\n \"sort\": \"SUGGEST\"\n \"createdAt\": \"2026-02-03\"\n },\n {\n \"adminName\": \"\",\n \"sort\": \"REVIEW\"\n \"createdAt\": \"2026-02-03\"\n }\n]\n```\n\n**Status:**\n - 성공 시 200(OK)\n", + "operationId": "getMyStampData", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListTemporaryQrResponseDTO" + } + } + } + } + } + } + }, + "/suggestion/list": { + "get": { + "tags": ["Suggestion"], + "summary": "제휴 건의 조회 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-24c1197c19ed8083bf8be4b6a6a43f18)\n- 현재 로그인한 관리자가 받은 모든 제휴 건의를 조회합니다.\n- 제휴 건의는 작성일 기준 최신순으로 조회.\n- enrollmentStatus로 재학 상태 표시(ENROLLED, LEAVE, GRADUATED)\n- 성공 시 200(OK)과 Suggestion 객체 반환.\n\n**Response:**\n - `suggestionId` (Long): 건의 ID\n - `createdAt` (LocalDateTime): 건의 작성일\n - `storeName` (String): 희망 가게 이름\n - `content` (String): 건의 내용\n - `studentMajor` (Long): 건의자의 학부/학과\n - `enrollmentStatus` (EnrollmentStatus): 재학 상태\n", + "operationId": "getSuggestions", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListGetSuggestionResponseDTO" + } + } + } + } + } + } + }, + "/suggestion/admin": { + "get": { + "tags": ["Suggestion"], + "summary": "제휴 건의대상 조회 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-2621197c19ed808c9627fcb7f58f4538)\n- 현재 로그인한 학생이 건의할 수 있는 관리자를 조회합니다.\n- 성공 시 200(OK)과 SuggestionAdmins 객체 반환.\n\n**Response:**\n - `adminId` (Long): 총학생회 ID\n - `adminName` (String): 총학생회 이름\n - `departId` (Long): 단과대학 학생회 ID\n - `departName` (String): 단과대학 학생회 이름\n - `majorId` (Long): 학부/학과 학생회 ID\n - `majorName` (String): 학부/학과 학생회 이름\n", + "operationId": "getSuggestionAdmins", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseGetSuggestionAdminsDTO" + } + } + } + } + } + } + }, + "/students/usage": { + "get": { + "tags": ["Student"], + "summary": "리뷰되지 않은 제휴 사용내역 조회 API", + "description": "# [v1.0 (2025-09-10)](https://www.notion.so/_-24c1197c19ed809a9d81e8f928e8355f?source=copy_link)\n- `multipart/form-data`로 호출합니다.\n\n**Request:**\n - page : (Int, required) 이상의 정수 \n - size : (Int, required) 기본 값 10 \n - sort : (String, required) createdAt/desc 문자열로 입력\n\n**Response:**\n - 성공 시 리뷰 되지 않은 partnership Usage 내역 반환 \n - StudentResponseTO.UsageDetailDTO 객체 반환 \n", + "operationId": "getUnreviewedUsage", + "parameters": [ + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePageUsageDetail" + } + } + } + } + } + } + }, + "/students/usable": { + "get": { + "tags": ["Student"], + "summary": "사용자의 이용 가능한 제휴 조회 API", + "description": "# [v1.0 (2025-10-30)](https://clumsy-seeder-416.notion.site/API-29c1197c19ed8030b1f5e2a744416651?source=copy_link)\n- 현재 로그인한 사용자가 이용 가능한 제휴 목록을 조회합니다.\n- 활성 상태인 제휴만 반환합니다.\n\n**Request Parameters:**\n- `all` (Boolean, optional): 전체 조회 여부 - 기본값: false\n - true: 모든 이용 가능한 제휴 조회\n - false: 최대 2개만 조회\n\n**Response:**\n- 성공 시 200(OK)와 이용 가능한 제휴 목록 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 404(NOT_FOUND): 사용자 정보를 찾을 수 없음", + "operationId": "getUsablePartnership", + "parameters": [ + { + "name": "all", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListUsablePartnershipDTO" + } + } + } + } + } + } + }, + "/students/partnerships/{year}/{month}": { + "get": { + "tags": ["Student"], + "summary": "월별 제휴 사용내역 조회 API", + "description": "# [v1.0 (2025-09-09)](https://www.notion.so/_-2241197c19ed8134bd49d8841e841634?source=copy_link)\n- `multipart/form-data`로 호출합니다.\n\n**Request Parts:**\n - `year` (Integer, required): 년도\n - `month` (Long, required): 월\n\n**Response:**\n - 성공 시 partnership Usage 내역 반환 \n - 해당 storeId, storeName 반환 - 해당 월에 사용한 제휴 수 반환", + "operationId": "getMyPartnership", + "parameters": [ + { + "name": "year", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "month", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseMyPartnership" + } + } + } + } + } + } + }, + "/store/{storeId}/papers": { + "get": { + "tags": ["Store"], + "summary": "제휴 컨텐츠 조회 API", + "description": "# [v1.0 (2026-02-14)](https://clumsy-seeder-416.notion.site/2361197c19ed8019b8b8cb054cd3135b?source=copy_link)\n- 유저가 속한 단과대 및 학부의 `admin_id`와 요청한 `store_id`를 매칭하여 적용 가능한 제휴 컨텐츠를 조회합니다.\n- QR 코드 스캔 후 유저에게 실제로 보여줄 혜택(Paper) 목록을 가져올 때 사용됩니다.\n\n**Path Variable:**\n - `storeId` (Long, required): QR에서 추출한 제휴 매장 ID\n\n**Query Parameters:**\n - (없음) - 유저 정보는 토큰(@AuthenticationPrincipal)을 통해 식별합니다.\n\n**Response (PaperResponseDTO):**\n - `storeId` (Long): 매장 고유 ID\n - `storeName` (String): 매장 이름\n - `partnershipContents` (List): 제휴 컨텐츠 상세 목록\n - `adminId` (Long): 혜택 제공자 ID\n - `adminName` (String): 혜택 제공자 이름 (예: OO대학 학생회)\n - `paperContent` (String): 제휴 혜택 상세 설명\n - `contentId` (Long): 컨텐츠 고유 ID\n - `goods` (List): 제공되는 상품/서비스 리스트\n - `people` (Integer): 사용 가능 인원\n - `cost` (Long): 유저 부담 금액 (0이면 무료)\n\n**Error Cases:**\n - 성공: 200 OK, `isSuccess=true`, `result=PaperResponseDTO` (제휴 컨텐츠 상세 정보)\n - 실패: \n - 404 NOT_FOUND: 해당 매장을 찾을 수 없거나 유효한 제휴 컨텐츠가 없는 경우\n - 403 FORBIDDEN: 유저 권한이 없거나 인증에 실패한 경우", + "operationId": "getStorePaperContent", + "parameters": [ + { + "name": "storeId", + "in": "path", + "description": "QR에서 추출한 storeId를 입력해주세요", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePaperResponseDTO" + } + } + } + } + } + } + }, + "/store/stamp-ranking": { + "get": { + "tags": ["Store"], + "summary": "스탬프 기준 인기 매장 랭킹 조회 API", + "description": "# [v1.0 (2026-02-09)](https://clumsy-seeder-416.notion.site/API-3001197c19ed806a99a8fa3e795aba8e?source=copy_link)\n- 하루 동안 스탬프가 많이 적립된 매장 순위를 조회합니다.\n- 최대 10개까지 반환\n- 로그인 필요 없음\n\n**Response:**\n - `rankings` (List): 매장 랭킹 목록\n - `storeId` (Long): 매장 ID\n - `storeName` (String): 매장 이름\n - `stampCount` (Long): 스탬프 적립 횟수", + "operationId": "getStampRanking", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseStampRankingListDTO" + } + } + } + } + } + } + }, + "/store/ranking": { + "get": { + "tags": ["Store"], + "summary": "내 가게 순위 조회 API", + "description": "# [v1.0 (2025-12-23)](https://www.notion.so/내-가게-순위-API_문서)\n- partnerId로 접근 가능합니다.\n- 로그인된 파트너만 조회 가능\n\n**Response:**\n - `rank` (Long): 그 주 순위 (1부터)\n - `usageCount` (Long): 그 주 사용 건수", + "operationId": "getWeeklyRank", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseWeeklyRankResponseDTO" + } + } + } + } + } + } + }, + "/store/ranking/weekly": { + "get": { + "tags": ["Store"], + "summary": "내 가게 순위 6주치 조회 API", + "description": "partnerId로 접근해주세요", + "operationId": "getWeeklyRankByPartnerId", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListWeeklyRankResponseDTO" + } + } + } + } + } + } + }, + "/store/best": { + "get": { + "tags": ["Store"], + "summary": "오늘 인기 매장 조회 API", + "description": "# [v1.0 (2025-12-23)](https://clumsy-seeder-416.notion.site/Today-22b1197c19ed80aebfc3e6b337d02ece?source=copy_link)\n- 오늘 기준 인기 매장 목록을 조회합니다.\n- 로그인 필요 없음\n\n**Response:**\n - `bestStores` (List): 오늘 가장 인기 있는 매장 이름 목록", + "operationId": "getTodayBestStore", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseTodayBestResponseDTO" + } + } + } + } + } + } + }, + "/reviews/student": { + "get": { + "tags": ["Review"], + "summary": "내가 쓴 리뷰 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/22b1197c19ed8057b158c88f6153d073)\n- 로그인한 학생 사용자가 작성한 리뷰 목록을 페이징하여 조회합니다.", + "operationId": "checkStudent", + "parameters": [ + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePageCheckReviewResponseDTO" + } + } + } + } + } + } + }, + "/reviews/store/{storeId}": { + "get": { + "tags": ["Review"], + "summary": "가게 리뷰 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2681197c19ed80038db3f7dd357623ff)\n- 특정 storeId를 기반으로 해당 가게의 모든 리뷰를 조회합니다.", + "operationId": "checkStoreReview", + "parameters": [ + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } + }, + { + "name": "storeId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePageCheckReviewResponseDTO" + } + } + } + } + } + } + }, + "/reviews/partner": { + "get": { + "tags": ["Review"], + "summary": "내 가게 리뷰 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-2241197c19ed8130b89ad5a77f3e8b2c)\n- 로그인한 파트너 계정의 가게에 달린 리뷰 목록을 페이징하여 조회합니다.", + "operationId": "checkPartnerReview", + "parameters": [ + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePageCheckReviewResponseDTO" + } + } + } + } + } + } + }, + "/reviews/average": { + "get": { + "tags": ["Review"], + "summary": "내 가게 리뷰 평균 조회 API (파트너)", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/API-2681197c19ed80df9f2ac100812c7f44)\n- 파트너 로그인 시 본인 가게의 평균 평점을 조회합니다.", + "operationId": "getMyStoreAverage", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseStandardScoreResponseDTO" + } + } + } + } + } + } + }, + "/reviews/average/{storeId}": { + "get": { + "tags": ["Review"], + "summary": "가게 리뷰 평균 조회 API (ID 기반)", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2ef1197c19ed80a5a08fd4d2aa031e5f)\n- 특정 storeId 기반으로 해당 가게의 리뷰 평점을 조회합니다.", + "operationId": "getStandardScore", + "parameters": [ + { + "name": "storeId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseStandardScoreResponseDTO" + } + } + } + } + } + } + }, + "/partnership/{partnershipId}": { + "get": { + "tags": ["Partnership"], + "summary": "제휴 상세조회 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2371197c19ed80cdac8beb2ffddb2f61)\n- 제휴 제안서의 내용을 조회합니다.\n- 적용할 상태 입력 (ACTIVE/SUSPEND/INACTIVE).\n\n**Parameters:**\n - `partnershipId` (Long, required): 내용을 조회할 제안서 ID\n\n**Response:**\n - 성공 시 200(OK)과 `GetPartnershipDetailResponse` 객체 반환.\n - `partnershipId` (Long): 제안서 ID\n - `updatedAt` (LocalDateTime): 업데이트된 시간\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", + "operationId": "getPartnership", + "parameters": [ + { + "name": "partnershipId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePartnershipDetailResponseDTO" + } + } + } + } + } + } + }, + "/partnership/suspended": { + "get": { + "tags": ["Partnership"], + "summary": "대기 중인 제휴 계약서 조회 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-24f1197c19ed802784fddadbbd3ea2c6)\n- 현재 로그인한 관리자와 제휴 중인 제안서 중 SUSPEND 상태인 제안서를 모두 조회합니다.\n\n**Response:**\n - 성공 시 200(OK)과 `SuspendedPaper` 객체 반환.\n - `paperId` (Long): 제안서 ID\n - `partnerName` (String): 제휴업체 이름\n - `createdAt` (LocalDateTime): 제휴 생성 일자\n", + "operationId": "suspendPartnership", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListSuspendedPaperResponseDTO" + } + } + } + } + } + } + }, + "/partnership/partner": { + "get": { + "tags": ["Partnership"], + "summary": "제휴 중인 관리자 조회 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-24f1197c19ed802784fddadbbd3ea2c6)\n- 현재 로그인한 제휴업체와 제휴 중인 관리자를 조회합니다.\n- 전체를 조회하려면 all을 true로, 가장 최근 두 건을 조회하려면 all을 false로 설정.\n\n**Parameters:**\n - `all` (boolean, required): 조회 옵션\n\n**Response:**\n - 성공 시 200(OK)과 `WritePartnershipResponse` 객체 반환.\n - `partnershipId` (Long): 제안서 ID\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `storeName` (String): 가게 이름\n - `adminName` (String): 관리자 이름\n - `isActivated` (ActivationStatus): 제안서 활성화 여부\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", + "operationId": "listForPartner", + "parameters": [ + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePageWritePartnershipResponseDTO" + } + } + } + } + } + } + }, + "/partnership/check/partner/{adminId}": { + "get": { + "tags": ["Partnership"], + "summary": "채팅방 내 제휴 확인 API(제휴업체용)", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed8078af77d65bfcc09087)\n- 현재 로그인한 제휴업체와 파라미터로 받은 adminId를 가진 관리자 간에 제휴를 조회합니다.\n- 비활성화 되지 않은 가장 최근 제휴 1건 조회.\n\n**Parameters:**\n - `adminId` (Long, required): 관리자 ID\n\n**Response:**\n - 성공 시 200(OK)과 `PartnerPartnershipWithAdminResponse` 객체 반환.\n - `paperId` (Long): 제안서 ID\n - `isPartnered` (boolean): 제휴 여부\n - `status` (String): 제휴 상태\n - `adminId` (Long): 관리자 ID\n - `adminName` (String): 관리자 이름\n - `adminAddress` (String): 관리자 주소\n", + "operationId": "checkPartnerPartnership", + "parameters": [ + { + "name": "adminId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePartnerPartnershipCheckResponseDTO" + } + } + } + } + } + } + }, + "/partnership/check/admin/{partnerId}": { + "get": { + "tags": ["Partnership"], + "summary": "채팅방 내 제휴 확인 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-31f1197c19ed8017bceced3b3d65c0d7?source=copy_link)\n- 현재 로그인한 관리자와 파라미터로 받은 partnerId를 가진 제휴업체 간에 제휴를 조회합니다.\n- 비활성화 되지 않은 가장 최근 제휴 1건 조회.\n\n**Parameters:**\n - `partnerId` (Long, required): 제휴업체 ID\n\n**Response:**\n - 성공 시 200(OK)과 `AdminPartnershipWithPartnerResponse` 객체 반환.\n - `paperId` (Long): 제안서 ID\n - `isPartnered` (boolean): 제휴 여부\n - `status` (String): 제휴 상태\n - `partnerId` (Long): 제휴업체 ID\n - `partnerName` (String): 제휴업체 이름\n - `partnerAddress` (String): 제휴업체 주소\n", + "operationId": "checkAdminPartnership", + "parameters": [ + { + "name": "partnerId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseAdminPartnershipCheckResponseDTO" + } + } + } + } + } + } + }, + "/partnership/admin": { + "get": { + "tags": ["Partnership"], + "summary": "제휴 중인 가게 조회 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-2241197c19ed81b1b9adf724adc4600c)\n- 현재 로그인한 관리자와 제휴 중인 가게를 조회합니다.\n- 전체를 조회하려면 all을 true로, 가장 최근 두 건을 조회하려면 all을 false로 설정.\n\n**Parameters:**\n - `all` (boolean, required): 조회 옵션\n\n**Response:**\n - 성공 시 200(OK)과 `WritePartnershipResponse` 객체 반환.\n - `partnershipId` (Long): 제안서 ID\n - `partnershipPeriodStart` (LocalDate): 제휴 시작일\n - `partnershipPeriodEnd` (LocalDate): 제휴 마감일\n - `adminId` (Long): 관리자 ID\n - `partnerId` (Long): 제휴업체 ID\n - `storeId` (Long): 가게 ID\n - `storeName` (String): 가게 이름\n - `adminName` (String): 관리자 이름\n - `isActivated` (ActivationStatus): 제안서 활성화 여부\n - `options` (JSON): 제휴 옵션\n - `optionType` (OptionType): 제공 서비스 종류 (서비스 제공, 할인)\n - `criterionType` (CriterionType): 서비스 제공 기준 (금액, 인원)\n - `anotherType` (Boolean): 기타 제공 서비스\n - `people` (Integer): 서비스 제공 기준 인원 수\n - `cost` (Integer): 서비스 제공 기준 금액\n - `note` (String): 기타 유형 제휴 옵션 문구\n - `category` (String): 서비스 카테고리, 서비스 제공 항목이 여러 개 일 때 작성\n - `discountRate` (Long): 서비스 제공 인원 수\n - `goods` (JSON): 서비스 제공 항목\n - `goodsId` (Long): 서비스 제공 항목 ID\n - `goodsName` (String): 서비스 제공 항목명\n", + "operationId": "listForAdmin", + "parameters": [ + { + "name": "pageable", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/Pageable" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePageWritePartnershipResponseDTO" + } + } + } + } + } + } + }, + "/partner/admin-recommend": { + "get": { + "tags": ["Partner"], + "summary": "관리자 추천 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed80368a9edf1f6e92ea38)\n- 현재 로그인 한 제휴업체와 제휴하지 않은 관리자 중 최대 두 곳을 랜덤으로 조회합니다.\n\n**Response:**\n - 성공 시 200(OK)과 `RandomAdminResponse` 객체(최대 두 개) 반환\n - `adminId` (Long): 관리자 ID\n - `adminAddress` (String): 관리자 주소\n - `adminDetailAddress` (String): 관리자 상세주소\n - `adminName` (String): 관리자 상호명\n - `adminUrl` (String): 관리자 카카오맵 URL\n - `adminPhone` (String): 관리자 전화번호\n", + "operationId": "randomAdminRecommend", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponsePartnerResponseDTO" + } + } + } + } + } + } + }, + "/notifications": { + "get": { + "tags": ["Notification"], + "summary": "알림 목록 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2491197c19ed8091b349ef0ef4bb0f60?source=copy_link)\n- 본인의 알림 목록을 상태별로 조회합니다.\n\n**Request Parameters:**\n- `status` (String, optional): 알림 상태 (all, unread) - 기본값: all\n- `page` (Integer, optional): 페이지 번호 (1 이상) - 기본값: 1\n- `size` (Integer, optional): 페이지 크기 - 기본값: 20\n\n**Response:**\n- 성공 시 200(OK)과 알림 목록 반환\n- 400(BAD_REQUEST): 잘못된 상태 값 또는 페이지 번호\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", + "operationId": "list_1", + "parameters": [ + { + "name": "status", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "all" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 1 + } + }, + { + "name": "size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 20 + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseMapStringObject" + } + } + } + } + } + } + }, + "/notifications/unread-exists": { + "get": { + "tags": ["Notification"], + "summary": "읽지 않은 알림 존재 여부 조회 API", + "description": "# [v1.0 (2025-09-02)](https://clumsy-seeder-416.notion.site/2691197c19ed809a81fec6eb3282ec3a?source=copy_link)\n- 현재 로그인 사용자의 읽지 않은 알림 존재 여부를 반환합니다.\n- 알림 배지 표시 여부를 결정하는 데 사용됩니다.\n\n**Response:**\n- 성공 시 200(OK)와 존재 여부 반환\n- true: 읽지 않은 알림 있음, false: 모든 알림 읽음\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", + "operationId": "unreadExists", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBoolean" + } + } + } + } + } + } + }, + "/notifications/settings": { + "get": { + "tags": ["Notification"], + "summary": "알림 현재 설정 조회 API", + "description": "# [v1.0 (2025-09-02)](https://clumsy-seeder-416.notion.site/2691197c19ed80de9b92d96db3608cdf?source=copy_link)\n- 현재 로그인 사용자의 알림 설정 상태를 반환합니다.\n- 모든 알림 유형에 대한 ON/OFF 상태를 확인할 수 있습니다.\n\n**Response:**\n- 성공 시 200(OK)와 알림 설정 상태 반환\n- 각 알림 유형별 true/false 값 포함\n- 401(UNAUTHORIZED): 인증되지 않은 사용자", + "operationId": "getSettings", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseNotificationSettingsResponseDTO" + } + } + } + } + } + } + }, + "/map/search": { + "get": { + "tags": ["Map"], + "summary": "검색어 기반 장소 조회 API", + "description": "# [v1.3 (2025-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed8017adf1f3d711bab3d4)\n- 로그인한 유저의 역할과 검색어에 따라 Map 객체를 반환합니다.\n- 검색어(searchKeyword) 입력.\n- 성공 시 200(OK)과 Map 객체 반환.\n\n**Request Parts:**\n - `searchKeyword` (String, required): 검색어\n\n**Response:**\n - `User`: 가게 조회\n - `storeId` (Long): 가게 ID\n - `name` (String): 가게 이름\n - `address` (String): 가게 주소\n - `rate` (Integer): 가게 별점\n - `hasPartner` (boolean): 제휴업체인지 여부\n - `latitude` (Double): 가게 위치 위도\n - `longitude` (Double): 가게 위치 경도\n - `profileUrl` (String): 가게 카카오맵 URL\n - `phoneNumber` (String): 가게 전화번호\n - `partnerships` (Array): 제휴 정보 목록\n - `adminId` (Long): 관리자 ID\n - `adminName` (String): 관리자 이름\n - `benefits` (Array): 혜택 목록\n - `Admin`: 제휴업체 조회\n - `partnerId` (Long): 제휴업체 ID\n - `name` (String): 제휴업체 이름\n - `address` (String): 제휴업체 주소\n - `isPartnered` (boolean): 관리자와 제휴 여부\n - `partnershipId` (Long): 제휴 ID\n - `partnershipStartDate` (LocalDate): 제휴 시작일\n - `partnershipEndDate` (LocalDate): 제휴 마감일\n - `latitude` (Double): 제휴업체 위도\n - `longitude` (Double): 제휴업체 경도\n - `profileUrl` (String): 제휴업체 카카오맵 Url\n - `phoneNumber` (String): 제휴업체 전화번호\n - `Partner`: 관리자 조회\n - `adminId` (Long): 관리자 ID\n - `name` (String): 관리자 이름\n - `address` (String): 관리자 주소\n - `isPartnered` (boolean): 제휴업체와 제휴 여부\n - `partnershipId` (Long): 제휴 ID\n - `partnershipStartDate` (LocalDate): 제휴 시작일\n - `partnershipEndDate` (LocalDate): 제휴 마감일\n - `latitude` (Double): 관리자 위도\n - `longitude` (Double): 관리자 경도\n - `profileUrl` (String): 관리자 카카오맵 Url\n - `phoneNumber` (String): 관리자 전화번호\n", + "operationId": "getLocationsByKeyword", + "parameters": [ + { + "name": "searchKeyword", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseObject" + } + } + } + } + } + } + }, + "/map/place": { + "get": { + "tags": ["Map"], + "summary": "카카오맵 기반 장소 검색 API", + "description": "# [v1.3 (2025-01-04)](https://clumsy-seeder-416.notion.site/25d1197c19ed807eb7a7c5ede2e75040)\n- 검색어에 따라 Map 객체를 반환합니다.\n- 검색어(searchKeyword) 입력.\n- limit을 통해 Map 객체 수 제한.\n- 성공 시 200(OK)과 Map 객체 반환.\n\n**Request Parts:**\n - `searchKeyword` (String, required): 검색어\n - `limit` (Integer): 결과 객체 수\n\n**Response:**\n - `placeId` (String): kakao place ID\n - `name` (String): kakao place 이름\n - `category` (String): kakao 카테고리 또는 그룹 이름\n - `address` (String): 지번 주소\n - `roadAddress` (String): 도로명 주소\n - `phone` (String): 장소 전화번호\n - `placeUrl` (String): kakao place 상세 URL\n - `latitude` (Double): 장소 위도\n - `longitude` (Double): 장소 경도\n - `distance` (Integer): 장소의 m 좌표 (좌표바이어스/카테고리 검색 시 제공)\n", + "operationId": "search", + "parameters": [ + { + "name": "searchKeyword", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListPlaceSuggestionDTO" + } + } + } + } + } + } + }, + "/map/nearby": { + "get": { + "tags": ["Map"], + "summary": "현재 위치 기반 주변 장소 조회 API", + "description": "# [v1.3 (2025-01-04)](https://clumsy-seeder-416.notion.site/2441197c19ed80bcb55fcad675dd9837?source=copy_link)\n- 로그인한 유저의 역할에 따라 Map 객체를 반환합니다.\n- 경도, 위도 순서로 입력한 Viewport 객체 입력.\n- 성공 시 200(OK)과 Map 객체 반환.\n\n**Request Body:**\n - `viewport` 객체 (JSON, required): 공간인덱싱을 위한 경도, 위도 객체\n - `lng1` (double): 좌 상단 경도\n - `lat1` (double): 좌 상단 위도\n - `lng2` (double): 우 상단 경도\n - `lat2` (double): 우 상단 위도\n - `lng3` (double): 우 하단 경도\n - `lat3` (double): 우 하단 위도\n - `lng4` (double): 좌 하단 경도\n - `lat4` (double): 좌 하단 위도\n\n**Response:**\n - `User`: 가게 조회\n - `storeId` (Long): 가게 ID\n - `name` (String): 가게 이름\n - `address` (String): 가게 주소\n - `rate` (Integer): 가게 별점\n - `hasPartner` (boolean): 제휴업체인지 여부\n - `latitude` (Double): 가게 위치 위도\n - `longitude` (Double): 가게 위치 경도\n - `profileUrl` (String): 가게 카카오맵 URL\n - `phoneNumber` (String): 가게 전화번호\n - `partnerships` (Array): 제휴 정보 목록\n - `adminId` (Long): 관리자 ID\n - `adminName` (String): 관리자 이름\n - `benefits` (Array): 혜택 목록\n - `Admin`: 제휴업체 조회\n - `partnerId` (Long): 제휴업체 ID\n - `name` (String): 제휴업체 이름\n - `address` (String): 제휴업체 주소\n - `isPartnered` (boolean): 관리자와 제휴 여부\n - `partnershipId` (Long): 제휴 ID\n - `partnershipStartDate` (LocalDate): 제휴 시작일\n - `partnershipEndDate` (LocalDate): 제휴 마감일\n - `latitude` (Double): 제휴업체 위도\n - `longitude` (Double): 제휴업체 경도\n - `profileUrl` (String): 제휴업체 카카오맵 Url\n - `phoneNumber` (String): 제휴업체 전화번호\n - `Partner`: 관리자 조회\n - `adminId` (Long): 관리자 ID\n - `name` (String): 관리자 이름\n - `address` (String): 관리자 주소\n - `isPartnered` (boolean): 제휴업체와 제휴 여부\n - `partnershipId` (Long): 제휴 ID\n - `partnershipStartDate` (LocalDate): 제휴 시작일\n - `partnershipEndDate` (LocalDate): 제휴 마감일\n - `latitude` (Double): 관리자 위도\n - `longitude` (Double): 관리자 경도\n - `profileUrl` (String): 관리자 카카오맵 Url\n - `phoneNumber` (String): 관리자 전화번호\n", + "operationId": "getLocations", + "parameters": [ + { + "name": "viewport", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/MapRequestDTO" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseObject" + } + } + } + } + } + } + }, + "/inquiries/{inquiryId}": { + "get": { + "tags": ["Inquiry"], + "summary": "문의 내역 단건 상세 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed800f8a1fffc5a101f3c0?source=copy_link)\n- 본인의 문의 내역 중 1건의 문의를 상세 조회합니다.\n\n**Path Variable:**\n- `inquiryId` (Long, required): 문의 ID\n\n**Response:**\n- 성공 시 200(OK)과 문의 상세 정보 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 403(FORBIDDEN): 다른 사용자의 문의 접근 시도\n- 404(NOT_FOUND): 존재하지 않는 문의 ID", + "operationId": "get", + "parameters": [ + { + "name": "inquiryId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseInquiryResponseDTO" + } + } + } + } + } + } + }, + "/chat/rooms/{roomId}/messages": { + "get": { + "tags": ["Chatting"], + "summary": "채팅방 상세 조회 API", + "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed800eab45c35073761c97?v=2241197c19ed8134b64f000cc26c5d31&p=2241197c19ed81399395fd66f73730af&pm=s)\n- 채팅방을 클릭했을 때 메시지를 조회합니다.\n\n**Path Variable:**\n- roomId (Long, required): 채팅방 ID\n", + "operationId": "getChatHistory", + "parameters": [ + { + "name": "roomId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseChatHistoryResponseDTO" + } + } + } + } + } + } + }, + "/chat/check/block/{opponentId}": { + "get": { + "tags": ["Chatting"], + "summary": "상대방 차단 여부 확인 API", + "description": "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed80769521eab9660ac53f)\n- 상대방을 차단했는지 검사합니다.\n\n**Path Variable:**\n- opponentId (Long, required): 상대방 ID\n", + "operationId": "checkBlock", + "parameters": [ + { + "name": "opponentId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCheckBlockMemberDTO" + } + } + } + } + } + } + }, + "/chat/block-list": { + "get": { + "tags": ["Chatting"], + "summary": "차단한 대상 조회 API", + "description": "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed8000b047d9857bcbbb2f)\n- 차단한 대상을 조회합니다.\n", + "operationId": "getBlockList", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseListBlockMemberDTO" + } + } + } + } + } + } + }, + "/admin/partner-recommend": { + "get": { + "tags": ["Admin"], + "summary": "제휴업체 추천 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed80f5b05cffcfecef9c24?source=copy_link)\n- 현재 로그인 한 관리자와 제휴하지 않은 제휴업체 중 한 곳을 랜덤으로 조회합니다.\n\n**Response:**\n - 성공 시 200(OK)과 `RandomPartnerResponse` 객체 반환\n - `partnerId` (Long): 제휴업체 ID\n - `partnerAddress` (String): 제휴업체 주소\n - `partnerDetailAddress` (String): 제휴업체 상세주소\n - `partnerName` (String): 제휴업체 상호명\n - `partnerUrl` (String): 제휴업체 카카오맵 URL\n - `partnerPhone` (String): 제휴업체 전화번호\n", + "operationId": "randomPartnerRecommend", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseAdminResponseDTO" + } + } + } + } + } + } + }, + "/admin/dashBoard": { + "get": { + "tags": ["Admin Dashboard"], + "summary": "누적 가입자 수 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-24c1197c19ed8062be94fc08619b760f)\n- 관리자(Admin) 권한으로 접근하여 현재까지의 총 누적 가입자 수를 조회합니다.", + "operationId": "getCountAdmin", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCountAdminAuthResponseDTO" + } + } + } + } + } + } + }, + "/admin/dashBoard/usage": { + "get": { + "tags": ["Admin Dashboard"], + "summary": "제휴업체 누적 사용 수 내림차순 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-24e1197c19ed802b92eff5d4dc4dbe82)\n- 모든 제휴 업체의 누적 사용 현황을 사용량 내림차순 리스트로 반환합니다.", + "operationId": "getUsageList", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCountUsageListResponseDTO" + } + } + } + } + } + } + }, + "/admin/dashBoard/top": { + "get": { + "tags": ["Admin Dashboard"], + "summary": "제휴업체 누적별 1위 업체 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_1-2ef1197c19ed8010a49ce6313d137b4f)\n- 제휴 이용 횟수가 가장 많은 1위 업체의 정보를 조회합니다.", + "operationId": "getTopUsage", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCountUsageResponseDTO" + } + } + } + } + } + } + }, + "/admin/dashBoard/new": { + "get": { + "tags": ["Admin Dashboard"], + "summary": "신규 한 달 가입자 수 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-24c1197c19ed805db80fca98c38849d1)\n- 이번 달(매달 1일 초기화) 기준 신규 가입한 사용자 수를 조회합니다.", + "operationId": "getNewStudentCountAdmin", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseNewCountAdminResponseDTO" + } + } + } + } + } + } + }, + "/admin/dashBoard/countUser": { + "get": { + "tags": ["Admin Dashboard"], + "summary": "오늘 제휴 사용자 수 조회 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/_-24e1197c19ed80a283b1c336a1c3df72)\n- 금일 제휴 서비스를 이용한 총 사용자 수를 조회합니다.", + "operationId": "getCountUser", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseCountUsagePersonResponseDTO" + } + } + } + } + } + } + }, + "/reviews/{reviewId}": { + "delete": { + "tags": ["Review"], + "summary": "내가 쓴 리뷰 삭제 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/2241197c19ed81a58e93c9ba56f6cb9a)\n- 본인이 작성한 리뷰를 ID를 기반으로 삭제합니다.", + "operationId": "deleteReview", + "parameters": [ + { + "name": "reviewId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseDeleteReviewResponseDTO" + } + } + } + } + } + } + }, + "/partnership/proposal/delete/{paperId}": { + "delete": { + "tags": ["Partnership"], + "summary": "제휴 제안서 삭제 API", + "description": "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed80e58d30c469e4ba3146)\n- paperId와 관련된 모든 내용을 삭제합니다.\n- 성공 시 200(OK) 반환.\n\n**Parameters:**\n - `paperId` (Long, required): 삭제할 제안서 ID\n", + "operationId": "deletePartnership", + "parameters": [ + { + "name": "paperId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseVoid" + } + } + } + } + } + } + }, + "/device-tokens/{tokenId}": { + "delete": { + "tags": ["Device Token"], + "summary": "디바이스 토큰 등록 해제 API", + "description": "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed80b8b26be9e01d24c929?source=copy_link)\n- 로그아웃/탈퇴 시 호출해 디바이스 토큰 등록을 해제합니다.\n- 자신의 토큰만 해제가 가능합니다.\n\n**Path Variable:**\n- `tokenId` (Long, required): 해제할 디바이스 토큰 ID\n\n**Response:**\n- 성공 시 200(OK)과 성공 메시지 반환\n- 401(UNAUTHORIZED): 인증되지 않은 사용자\n- 403(FORBIDDEN): 다른 사용자의 토큰 해제 시도\n- 404(NOT_FOUND): 존재하지 않는 토큰 ID", + "operationId": "unregister", + "parameters": [ + { + "name": "tokenId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseString" + } + } + } + } + } + } + }, + "/chat/unblock": { + "delete": { + "tags": ["Chatting"], + "summary": "상대방 차단 해제 API", + "description": "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed80b6a93fcbe277fc934c?pvs=74)\n- 상대방을 차단 해제합니다. 다시 메시지를 주고받을 수 있습니다.\n\n**Request Parameter:**\n- opponentId (Long, required): 상대방 ID\n", + "operationId": "unblock", + "parameters": [ + { + "name": "opponentId", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseBlockMemberDTO" + } + } + } + } + } + } + }, + "/chat/rooms/{roomId}/leave": { + "delete": { + "tags": ["Chatting"], + "summary": "채팅방 나가기 API", + "description": "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed800eab45c35073761c97?v=2241197c19ed8134b64f000cc26c5d31&p=2371197c19ed8079a6e1c2331cb4f534&pm=s)\n- 채팅방을 나갑니다.\n- 참여자가 2명이면 채팅방이 살아있지만, 이미 한 명이 나갔다면 채팅방이 삭제됩니다.\n\n**Path Variable:**\n- roomId (Long, required): 채팅방 ID\n", + "operationId": "leaveChattingRoom", + "parameters": [ + { + "name": "roomId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/BaseResponseLeaveChattingRoomResponseDTO" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "BaseResponseNotificationSettingsResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/NotificationSettingsResponseDTO" + } + } + }, + "NotificationSettingsResponseDTO": { + "type": "object", + "properties": { + "settings": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + } + } + }, + "BaseResponseProfileImageResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/ProfileImageResponseDTO" + } + } + }, + "ProfileImageResponseDTO": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "업로드된 프로필 이미지 URL" + } + } + }, + "TemporaryQrRequestDTO": { + "type": "object", + "properties": { + "adminName": { + "type": "string", + "description": "adminName을 입력해주세요" + }, + "sort": { + "type": "string", + "description": "프론트 단에서 enum을 정의하여 REVIEW/SUGGEST 둘중 하나로 넘겨주세요", + "enum": ["REVIEW", "SUGGEST"] + } + }, + "required": ["sort"] + }, + "BaseResponseVoid": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "object" + } + } + }, + "WriteSuggestionRequestDTO": { + "type": "object", + "properties": { + "adminId": { + "type": "integer", + "format": "int64", + "description": "건의 대상 관리자 ID", + "example": 1 + }, + "storeName": { + "type": "string", + "description": "희망 가게 이름", + "example": "스타벅스 숭실대점" + }, + "benefit": { + "type": "string", + "description": "희망 혜택", + "example": "아메리카노 10% 할인" + } + }, + "required": ["adminId", "benefit", "storeName"] + }, + "BaseResponseWriteSuggestionResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/WriteSuggestionResponseDTO" + } + } + }, + "WriteSuggestionResponseDTO": { + "type": "object", + "properties": { + "suggestionId": { + "type": "integer", + "format": "int64", + "description": "건의 ID", + "example": 1 + }, + "userId": { + "type": "integer", + "format": "int64", + "description": "제안인 ID", + "example": 10 + }, + "adminId": { + "type": "integer", + "format": "int64", + "description": "건의 대상 관리자 ID", + "example": 1 + }, + "storeName": { + "type": "string", + "description": "희망 가게 이름", + "example": "스타벅스 숭실대점" + }, + "suggestionBenefit": { + "type": "string", + "description": "희망 혜택", + "example": "아메리카노 10% 할인" + } + }, + "required": [ + "adminId", + "storeName", + "suggestionBenefit", + "suggestionId", + "userId" + ] + }, + "BaseResponseString": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "string" + } + } + }, + "WriteReviewRequestDTO": { + "type": "object", + "properties": { + "content": { + "type": "string", + "description": "리뷰 내용", + "example": "정말 맛있었어요!" + }, + "rate": { + "type": "integer", + "format": "int32", + "description": "별점 (1-5)", + "example": 5, + "maximum": 5, + "minimum": 1 + }, + "storeId": { + "type": "integer", + "format": "int64", + "description": "가게 ID", + "example": 3 + }, + "partnerId": { + "type": "integer", + "format": "int64", + "description": "파트너 ID", + "example": 2 + }, + "partnershipUsageId": { + "type": "integer", + "format": "int64" + }, + "adminName": { + "type": "string" + } + } + }, + "BaseResponseWriteReviewResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/WriteReviewResponseDTO" + } + } + }, + "WriteReviewResponseDTO": { + "type": "object", + "properties": { + "reviewId": { + "type": "integer", + "format": "int64" + }, + "content": { + "type": "string" + }, + "rate": { + "type": "integer", + "format": "int32" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "memberId": { + "type": "integer", + "format": "int64" + }, + "reviewImageUrls": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "CreateContentReportRequest": { + "type": "object", + "properties": { + "targetType": { + "type": "string", + "enum": ["STUDENT_USER", "REVIEW", "SUGGESTION"] + }, + "targetId": { + "type": "integer", + "format": "int64" + }, + "reportType": { + "type": "string", + "enum": [ + "STUDENT_USER_SPAM", + "STUDENT_USER_INAPPROPRIATE_CONTENT", + "STUDENT_USER_HARASSMENT", + "STUDENT_USER_FRAUD", + "STUDENT_USER_PRIVACY_VIOLATION", + "STUDENT_USER_OTHER", + "REVIEW_INAPPROPRIATE_CONTENT", + "REVIEW_FALSE_INFORMATION", + "REVIEW_SPAM", + "SUGGESTION_INAPPROPRIATE_CONTENT", + "SUGGESTION_FALSE_INFORMATION", + "SUGGESTION_SPAM" + ] + } + }, + "required": ["reportType", "targetId", "targetType"] + }, + "BaseResponseCreateReportResponse": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CreateReportResponse" + } + } + }, + "CreateReportResponse": { + "type": "object", + "properties": { + "reportId": { + "type": "integer", + "format": "int64" + } + } + }, + "CreateStudentReportRequest": { + "type": "object", + "properties": { + "targetType": { + "type": "string", + "enum": ["STUDENT_USER", "REVIEW", "SUGGESTION"] + }, + "targetId": { + "type": "integer", + "format": "int64" + }, + "reportType": { + "type": "string", + "enum": [ + "STUDENT_USER_SPAM", + "STUDENT_USER_INAPPROPRIATE_CONTENT", + "STUDENT_USER_HARASSMENT", + "STUDENT_USER_FRAUD", + "STUDENT_USER_PRIVACY_VIOLATION", + "STUDENT_USER_OTHER", + "REVIEW_INAPPROPRIATE_CONTENT", + "REVIEW_FALSE_INFORMATION", + "REVIEW_SPAM", + "SUGGESTION_INAPPROPRIATE_CONTENT", + "SUGGESTION_FALSE_INFORMATION", + "SUGGESTION_SPAM" + ] + } + }, + "required": ["reportType", "targetId", "targetType"] + }, + "PartnershipFinalRequestDTO": { + "type": "object", + "properties": { + "storeId": { + "type": "integer", + "format": "int64", + "description": "storeId 입력" + }, + "adminId": { + "type": "integer", + "format": "int64", + "description": "adminId 입력" + }, + "tableNumber": { + "type": "string", + "description": "00~99 사이의 tableNumber를 입력해주세요" + }, + "adminName": { + "type": "string", + "description": "@@학생회 이름 그대로 입력해주세요" + }, + "placeName": { + "type": "string", + "description": "가게 명을 입력해주세요" + }, + "partnershipContent": { + "type": "string", + "description": "제휴 항목을 그대로 입력해주세요" + }, + "contentId": { + "type": "integer", + "format": "int64", + "description": "제휴 콘텐츠 아이디를 입력해주세요" + }, + "discount": { + "type": "integer", + "format": "int64" + }, + "userIds": { + "type": "array", + "description": "함께 인증한 유저들의 아이디를 입력해주세요(없을 시 공란)", + "items": { + "type": "integer", + "format": "int64" + } + } + }, + "required": [ + "adminId", + "adminName", + "contentId", + "partnershipContent", + "placeName", + "storeId", + "tableNumber" + ] + }, + "PartnershipDraftRequestDTO": { + "type": "object", + "properties": { + "partnerId": { + "type": "integer", + "format": "int64", + "description": "제휴 제안서를 작성할 제휴업체 ID", + "example": 101 + } + }, + "required": ["partnerId"] + }, + "BaseResponsePartnershipDraftResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PartnershipDraftResponseDTO" + } + } + }, + "PartnershipDraftResponseDTO": { + "type": "object", + "properties": { + "paperId": { + "type": "integer", + "format": "int64", + "description": "생성된 제안서 ID", + "example": 1001 + } + }, + "required": ["paperId"] + }, + "ManualPartnershipRequestDTO": { + "type": "object", + "properties": { + "storeName": { + "type": "string", + "description": "가게 이름", + "example": "역전할머니맥주 숭실대점" + }, + "selectedPlace": { + "$ref": "#/components/schemas/SelectedPlacePayload", + "description": "선택된 장소 정보 (카카오맵 검색 결과)" + }, + "storeDetailAddress": { + "type": "string", + "description": "가게 상세주소", + "example": "2층" + }, + "partnershipPeriodStart": { + "type": "string", + "format": "date", + "description": "제휴 시작일", + "example": "2024-01-01" + }, + "partnershipPeriodEnd": { + "type": "string", + "format": "date", + "description": "제휴 마감일", + "example": "2024-12-31" + }, + "options": { + "type": "array", + "description": "제휴 옵션 목록", + "items": { + "$ref": "#/components/schemas/PartnershipOptionRequestDTO" + } + } + }, + "required": [ + "options", + "partnershipPeriodEnd", + "partnershipPeriodStart", + "selectedPlace", + "storeName" + ] + }, + "PartnershipGoodsRequestDTO": { + "type": "object", + "properties": { + "goodsName": { + "type": "string", + "description": "서비스 제공 항목명", + "example": "아메리카노" + } + } + }, + "PartnershipOptionRequestDTO": { + "type": "object", + "properties": { + "optionType": { + "type": "string", + "description": "제공 서비스 종류 (SERVICE: 서비스 제공, DISCOUNT: 할인)", + "enum": ["SERVICE", "DISCOUNT"], + "example": "SERVICE" + }, + "criterionType": { + "type": "string", + "description": "서비스 제공 기준 (PRICE: 금액, HEADCOUNT: 인원)", + "enum": ["PRICE", "HEADCOUNT"], + "example": "HEADCOUNT" + }, + "anotherType": { + "type": "boolean", + "description": "기타 제공 서비스 여부", + "example": false + }, + "people": { + "type": "integer", + "format": "int32", + "description": "서비스 제공 기준 인원 수", + "example": 2 + }, + "cost": { + "type": "integer", + "format": "int64", + "description": "서비스 제공 기준 금액", + "example": 10000 + }, + "category": { + "type": "string", + "description": "서비스 카테고리 (서비스 제공 항목이 여러 개일 때 작성)", + "example": "음료" + }, + "discountRate": { + "type": "integer", + "format": "int64", + "description": "할인율", + "example": 10 + }, + "note": { + "type": "string", + "description": "기타 유형 제휴 옵션 문구", + "example": "웰컴 드링크 제공" + }, + "goods": { + "type": "array", + "description": "서비스 제공 항목 목록", + "items": { + "$ref": "#/components/schemas/PartnershipGoodsRequestDTO" + } + } + }, + "required": ["anotherType", "criterionType", "optionType"] + }, + "SelectedPlacePayload": { + "type": "object", + "properties": { + "placeId": { + "type": "string", + "description": "장소 ID", + "example": 12345678 + }, + "name": { + "type": "string", + "description": "장소 이름", + "example": "숭실대학교" + }, + "address": { + "type": "string", + "description": "장소 지번 주소", + "example": "서울특별시 동작구 상도로 369" + }, + "roadAddress": { + "type": "string", + "description": "장소 도로명 주소", + "example": "서울특별시 동작구 상도로 369" + }, + "latitude": { + "type": "number", + "format": "double", + "description": "장소 위도", + "example": 37.5 + }, + "longitude": { + "type": "number", + "format": "double", + "description": "장소 경도", + "example": 126.96 + } + } + }, + "BaseResponseManualPartnershipResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/ManualPartnershipResponseDTO" + } + } + }, + "ManualPartnershipResponseDTO": { + "type": "object", + "properties": { + "storeId": { + "type": "integer", + "format": "int64", + "description": "가게 ID", + "example": 201 + }, + "storeCreated": { + "type": "boolean", + "description": "가게가 DB에 신규 생성되었는지 여부", + "example": false + }, + "storeActivated": { + "type": "boolean", + "description": "가게가 재활성화되었는지 여부", + "example": false + }, + "status": { + "type": "string", + "description": "제휴 제안서의 상태", + "example": "SUSPEND" + }, + "contractImageUrl": { + "type": "string", + "description": "계약서 파일 URL", + "example": "https://example.com/contract.jpg" + }, + "partnership": { + "$ref": "#/components/schemas/WritePartnershipResponseDTO", + "description": "제휴 제안서 상세 정보" + } + }, + "required": ["contractImageUrl", "partnership", "status", "storeId"] + }, + "PartnershipGoodsResponseDTO": { + "type": "object", + "properties": { + "goodsId": { + "type": "integer", + "format": "int64", + "description": "서비스 제공 항목 ID", + "example": 501 + }, + "goodsName": { + "type": "string", + "description": "서비스 제공 항목명", + "example": "아메리카노" + } + }, + "required": ["goodsId", "goodsName"] + }, + "PartnershipOptionResponseDTO": { + "type": "object", + "properties": { + "optionType": { + "type": "string", + "description": "제공 서비스 종류 (SERVICE: 서비스 제공, DISCOUNT: 할인)", + "enum": ["SERVICE", "DISCOUNT"], + "example": "SERVICE" + }, + "criterionType": { + "type": "string", + "description": "서비스 제공 기준 (PRICE: 금액, HEADCOUNT: 인원)", + "enum": ["PRICE", "HEADCOUNT"], + "example": "HEADCOUNT" + }, + "anotherType": { + "type": "boolean", + "description": "기타 제공 서비스 여부", + "example": false + }, + "people": { + "type": "integer", + "format": "int32", + "description": "서비스 제공 기준 인원 수", + "example": 2 + }, + "cost": { + "type": "integer", + "format": "int64", + "description": "서비스 제공 기준 금액", + "example": 10000 + }, + "note": { + "type": "string", + "description": "기타 유형 제휴 옵션 문구", + "example": "웰컴 드링크 제공" + }, + "category": { + "type": "string", + "description": "서비스 카테고리 (서비스 제공 항목이 여러 개일 때 작성)", + "example": "음료" + }, + "discountRate": { + "type": "integer", + "format": "int64", + "description": "할인율", + "example": 10 + }, + "goods": { + "type": "array", + "description": "서비스 제공 항목 목록", + "items": { + "$ref": "#/components/schemas/PartnershipGoodsResponseDTO" + } + } + }, + "required": ["anotherType", "criterionType", "optionType"] + }, + "WritePartnershipResponseDTO": { + "type": "object", + "properties": { + "partnershipId": { + "type": "integer", + "format": "int64", + "description": "제안서 ID", + "example": 1001 + }, + "partnershipPeriodStart": { + "type": "string", + "format": "date", + "description": "제휴 시작일", + "example": "2024-01-01" + }, + "partnershipPeriodEnd": { + "type": "string", + "format": "date", + "description": "제휴 마감일", + "example": "2024-12-31" + }, + "adminId": { + "type": "integer", + "format": "int64", + "description": "관리자 ID", + "example": 101 + }, + "partnerId": { + "type": "integer", + "format": "int64", + "description": "제휴업체 ID", + "example": 201 + }, + "storeId": { + "type": "integer", + "format": "int64", + "description": "가게 ID", + "example": 301 + }, + "storeName": { + "type": "string", + "description": "가게 이름", + "example": "역전할머니맥주 숭실대점" + }, + "adminName": { + "type": "string", + "description": "관리자 이름", + "example": "숭실대학교 총학생회" + }, + "isActivated": { + "type": "string", + "description": "제안서 활성화 여부", + "enum": ["ACTIVE", "INACTIVE", "SUSPEND", "BLANK"], + "example": "SUSPEND" + }, + "options": { + "type": "array", + "description": "제휴 옵션 목록", + "items": { + "$ref": "#/components/schemas/PartnershipOptionResponseDTO" + } + } + }, + "required": [ + "adminId", + "adminName", + "isActivated", + "options", + "partnershipId", + "partnershipPeriodEnd", + "partnershipPeriodStart", + "storeId", + "storeName" + ] + }, + "QueueNotificationRequestDTO": { + "type": "object", + "properties": { + "receiverId": { + "type": "integer", + "format": "int64", + "description": "알림을 받을 멤버 ID", + "example": 1 + }, + "type": { + "type": "string", + "description": "알림 타입 (CHAT, PARTNER_SUGGESTION, ORDER, PARTNER_PROPOSAL)", + "example": "CHAT" + }, + "content": { + "type": "string", + "description": "알림 내용", + "example": "새로운 메시지가 있습니다." + }, + "title": { + "type": "string", + "description": "알림 제목", + "example": "채팅 알림" + }, + "deeplink": { + "type": "string", + "description": "앱 내 이동할 경로 (deeplink)", + "example": "app://chat/10" + }, + "roomId": { + "type": "integer", + "format": "int64", + "description": "채팅방 ID", + "example": 101 + }, + "senderName": { + "type": "string", + "description": "보낸 사람 이름", + "example": "홍길동" + }, + "message": { + "type": "string", + "description": "메시지 내용", + "example": "안녕하세요! 오늘 일정 확인 부탁드려요." + }, + "suggestionId": { + "type": "integer", + "format": "int64", + "description": "제휴 제안 ID", + "example": 2001 + }, + "orderId": { + "type": "integer", + "format": "int64", + "description": "주문 ID", + "example": 3001 + }, + "table_num": { + "type": "string", + "description": "테이블 번호", + "example": 11 + }, + "paper_content": { + "type": "string", + "description": "계약서 내용", + "example": "20,000원 이상 구매 시 10% 할인" + }, + "proposalId": { + "type": "integer", + "format": "int64", + "description": "제휴 제안 ID", + "example": 4001 + }, + "partner_name": { + "type": "string", + "description": "파트너 이름", + "example": "역전할머니맥주 송신대점" + }, + "refId": { + "type": "integer", + "format": "int64", + "description": "참조 ID (타입별로 roomId/orderId 등 대신 사용할 수 있음)", + "example": 9999 + } + }, + "required": ["receiverId", "type"] + }, + "InquiryCreateRequestDTO": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "문의 제목", + "example": "상호명 변경 요청드립니다." + }, + "content": { + "type": "string", + "description": "문의 내용", + "example": "안녕하세요. 역할맥입니다. 상호명을 변경하고 싶습니다." + }, + "email": { + "type": "string", + "description": "문의자 이메일", + "example": "assu@gmail.com" + } + }, + "required": ["content", "email", "title"] + }, + "BaseResponseLong": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "integer", + "format": "int64" + } + } + }, + "CreateChatRoomRequestDTO": { + "type": "object", + "description": "채팅방 생성 요청 DTO", + "properties": { + "adminId": { + "type": "integer", + "format": "int64", + "description": "사장님 id", + "example": 2 + }, + "partnerId": { + "type": "integer", + "format": "int64", + "description": "파트너 id", + "example": 12 + } + } + }, + "BaseResponseCreateChatRoomResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CreateChatRoomResponseDTO" + } + } + }, + "CreateChatRoomResponseDTO": { + "type": "object", + "properties": { + "roomId": { + "type": "integer", + "format": "int64" + }, + "adminViewName": { + "type": "string" + }, + "partnerViewName": { + "type": "string" + }, + "isNew": { + "type": "boolean" + } + } + }, + "BlockMemberRequestDTO": { + "type": "object", + "description": "채팅 차단 DTO", + "properties": { + "opponentId": { + "type": "integer", + "format": "int64", + "description": "차단할 사용자 ID", + "example": 12 + } + } + }, + "BaseResponseBlockMemberDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/BlockMemberDTO" + } + } + }, + "BlockMemberDTO": { + "type": "object", + "properties": { + "memberId": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "blockDate": { + "type": "string", + "format": "date-time" + } + } + }, + "CertificationGroupRequestDTO": { + "type": "object", + "properties": { + "people": { + "type": "integer", + "format": "int32", + "description": "1명 이상의 사람 수를 입력해주세요" + }, + "storeId": { + "type": "integer", + "format": "int64", + "description": "storeId를 입력해주세요" + }, + "adminId": { + "type": "integer", + "format": "int64", + "description": "adminId를 입력해주세요" + }, + "tableNumber": { + "type": "integer", + "format": "int32", + "description": "00~99 사이의 tableNumber를 입력해주세요" + } + }, + "required": ["adminId", "people", "storeId", "tableNumber"] + }, + "BaseResponseCertificationResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CertificationResponseDTO" + } + } + }, + "CertificationResponseDTO": { + "type": "object", + "properties": { + "sessionId": { + "type": "integer", + "format": "int64", + "description": "qr에 넣을 세션 아이디를 반환합니다." + } + } + }, + "CertificationPersonalRequestDTO": { + "type": "object", + "properties": { + "storeId": { + "type": "integer", + "format": "int64", + "description": "storeId를 입력해주세요" + }, + "adminId": { + "type": "integer", + "format": "int64", + "description": "adminId를 입력해주세요" + }, + "tableNumber": { + "type": "integer", + "format": "int32", + "description": "00~99 사이의 tableNumber를 입력해주세요" + } + }, + "required": ["adminId", "storeId", "tableNumber"] + }, + "BaseResponseRefreshResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/RefreshResponseDTO" + } + } + }, + "RefreshResponseDTO": { + "type": "object", + "description": "액세스 토큰 갱신 응답", + "properties": { + "memberId": { + "type": "integer", + "format": "int64", + "description": "회원 ID", + "example": 123 + }, + "newAccess": { + "type": "string", + "description": "새로운 액세스 토큰", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "newRefresh": { + "type": "string", + "description": "새로운 리프레시 토큰", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + } + } + }, + "USaintAuthRequestDTO": { + "type": "object", + "description": "유세인트 인증 요청", + "properties": { + "sToken": { + "type": "string", + "description": "유세인트 sToken", + "example": "Vy3zFySFx5FASz175Kx7AzKyuSFQEgQ..." + }, + "sIdno": { + "type": "string", + "description": "유세인트 sIdno", + "example": 20211438 + } + }, + "required": ["sIdno", "sToken"] + }, + "BaseResponseUSaintAuthResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/USaintAuthResponseDTO" + } + } + }, + "USaintAuthResponseDTO": { + "type": "object", + "description": "유세인트 인증 응답", + "properties": { + "studentNumber": { + "type": "string", + "description": "학번", + "example": 20211438 + }, + "name": { + "type": "string", + "description": "이름", + "example": "홍길동" + }, + "enrollmentStatus": { + "type": "string", + "description": "학적 상태", + "example": "재학" + }, + "yearSemester": { + "type": "string", + "description": "학년/학기", + "example": "4학년 1학기" + }, + "majorStr": { + "type": "string", + "description": "전공/학과" + } + } + }, + "StudentTokenAuthPayloadDTO": { + "type": "object", + "description": "학생 토큰 인증 페이로드", + "properties": { + "sToken": { + "type": "string", + "description": "유세인트 sToken", + "example": "Vy3zFySFx5FASz175Kx7AzKyuSFQEgQ..." + }, + "sIdno": { + "type": "string", + "description": "유세인트 sIdno", + "example": 20211438 + }, + "university": { + "type": "string", + "description": "대학교", + "enum": ["SSU"], + "example": "SSU" + } + }, + "required": ["sIdno", "sToken"] + }, + "StudentTokenSignUpRequestDTO": { + "type": "object", + "description": "학생 토큰 회원가입 요청", + "properties": { + "marketingAgree": { + "type": "boolean", + "description": "마케팅 수신 동의", + "example": true + }, + "locationAgree": { + "type": "boolean", + "description": "위치 정보 수집 동의", + "example": true + }, + "studentTokenAuth": { + "$ref": "#/components/schemas/StudentTokenAuthPayloadDTO", + "description": "학생 토큰 인증 정보" + } + }, + "required": ["locationAgree", "marketingAgree", "studentTokenAuth"] + }, + "BaseResponseSignUpResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/SignUpResponseDTO" + } + } + }, + "SignUpResponseDTO": { + "type": "object", + "description": "회원가입 성공 응답", + "properties": { + "memberId": { + "type": "integer", + "format": "int64", + "description": "회원 ID", + "example": 123 + }, + "role": { + "type": "string", + "description": "회원 역할", + "enum": ["STUDENT", "ADMIN", "PARTNER"], + "example": "STUDENT" + }, + "status": { + "type": "string", + "description": "회원 상태", + "enum": ["ACTIVE", "INACTIVE", "SUSPEND", "BLANK"], + "example": "ACTIVE" + }, + "tokens": { + "$ref": "#/components/schemas/TokensDTO", + "description": "액세스 토큰/리프레시 토큰" + }, + "basicInfo": { + "$ref": "#/components/schemas/UserBasicInfoDTO", + "description": "사용자 기본 정보 (캐싱용)" + } + } + }, + "TokensDTO": { + "type": "object", + "description": "JWT 토큰 정보", + "properties": { + "accessToken": { + "type": "string", + "description": "액세스 토큰", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "refreshToken": { + "type": "string", + "description": "리프레시 토큰", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + } + } + }, + "UserBasicInfoDTO": { + "type": "object", + "description": "사용자 기본 정보", + "properties": { + "name": { + "type": "string", + "description": "이름/업체명/단체명", + "example": "홍길동" + }, + "university": { + "type": "string", + "description": "대학교", + "example": "숭실대학교" + }, + "department": { + "type": "string", + "description": "단과대", + "example": "IT공과대학" + }, + "major": { + "type": "string", + "description": "전공/학과", + "example": "소프트웨어학부" + } + } + }, + "BaseResponseLoginResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/LoginResponseDTO" + } + } + }, + "LoginResponseDTO": { + "type": "object", + "description": "로그인 성공 응답", + "properties": { + "memberId": { + "type": "integer", + "format": "int64", + "description": "회원 ID", + "example": 123 + }, + "role": { + "type": "string", + "description": "회원 역할", + "enum": ["STUDENT", "ADMIN", "PARTNER"], + "example": "STUDENT" + }, + "status": { + "type": "string", + "description": "회원 상태", + "enum": ["ACTIVE", "INACTIVE", "SUSPEND", "BLANK"], + "example": "SUSPEND" + }, + "tokens": { + "$ref": "#/components/schemas/TokensDTO", + "description": "액세스 토큰/리프레시 토큰", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "basicInfo": { + "$ref": "#/components/schemas/UserBasicInfoDTO", + "description": "사용자 기본 정보 (캐싱용)" + } + } + }, + "PhoneAuthVerifyRequestDTO": { + "type": "object", + "description": "휴대폰 인증번호 검증 요청", + "properties": { + "phoneNumber": { + "type": "string", + "description": "인증받을 휴대폰 번호", + "example": "01012345678", + "pattern": "^010\\d{8}$" + }, + "authNumber": { + "type": "string", + "description": "발송받은 인증번호(OTP)", + "example": 123456 + } + }, + "required": ["authNumber", "phoneNumber"] + }, + "PhoneAuthSendRequestDTO": { + "type": "object", + "description": "휴대폰 번호 중복가입 확인 및 인증번호 발송 요청", + "properties": { + "phoneNumber": { + "type": "string", + "description": "인증번호를 받을 휴대폰 번호", + "example": "01012345678", + "pattern": "^010\\d{8}$" + } + }, + "required": ["phoneNumber"] + }, + "CommonAuthPayloadDTO": { + "type": "object", + "description": "공통 인증 정보 페이로드", + "properties": { + "email": { + "type": "string", + "description": "이메일 주소", + "example": "user@example.com" + }, + "password": { + "type": "string", + "description": "비밀번호(평문)", + "example": "P@ssw0rd!", + "maxLength": 72, + "minLength": 8 + }, + "department": { + "type": "string", + "description": "단과대", + "enum": [ + "HUMANITIES", + "NATURAL_SCIENCE", + "LAW", + "SOCIAL_SCIENCE", + "ECONOMICS", + "BUSINESS", + "ENGINEERING", + "IT", + "LIBERAL_STUDIES", + "AI" + ], + "example": "IT공과대학" + }, + "major": { + "type": "string", + "description": "전공/학과", + "enum": [ + "CHRISTIAN_STUDIES", + "KOREAN_LITERATURE", + "ENGLISH_LITERATURE", + "GERMAN_LITERATURE", + "FRENCH_LITERATURE", + "CHINESE_LITERATURE", + "JAPANESE_LITERATURE", + "PHILOSOPHY", + "HISTORY", + "CREATIVE_ARTS", + "SPORTS", + "MATHEMATICS", + "CHEMISTRY", + "BIOMEDICAL_SYSTEMS", + "PHYSICS", + "STATISTICS_ACTUARIAL", + "LAW", + "INTERNATIONAL_LAW", + "SOCIAL_WELFARE", + "POLITICAL_SCIENCE", + "MEDIA_COMMUNICATION", + "PUBLIC_ADMINISTRATION", + "INFORMATION_SOCIETY", + "LIFELONG_EDUCATION", + "ECONOMICS", + "FINANCIAL_ECONOMICS", + "GLOBAL_TRADE", + "INTERNATIONAL_TRADE", + "BUSINESS_ADMINISTRATION", + "ACCOUNTING", + "VENTURE_MANAGEMENT", + "WELFARE_MANAGEMENT", + "VENTURE_SME", + "FINANCE", + "INNOVATION_MANAGEMENT", + "ACCOUNTING_TAX", + "CHEMICAL_ENGINEERING", + "ELECTRICAL_ENGINEERING", + "ARCHITECTURE", + "INDUSTRIAL_INFO_SYSTEMS", + "MECHANICAL_ENGINEERING", + "MATERIALS_SCIENCE", + "SOFTWARE", + "GLOBAL_MEDIA", + "COMPUTER_SCIENCE", + "ELECTRONIC_ENGINEERING", + "AI_CONVERGENCE", + "DIGITAL_MEDIA", + "LIBERAL_STUDIES", + "AI_SOFTWARE", + "INFORMATION_SECURITY" + ], + "example": "소프트웨어학부" + }, + "university": { + "type": "string", + "description": "대학교", + "enum": ["SSU"], + "example": "SSU" + } + }, + "required": ["email", "password"] + }, + "CommonInfoPayloadDTO": { + "type": "object", + "description": "공통 정보 페이로드", + "properties": { + "name": { + "type": "string", + "description": "이름/업체명/단체명", + "example": "홍길동", + "maxLength": 50, + "minLength": 1 + }, + "detailAddress": { + "type": "string", + "description": "상세 주소", + "example": "101호", + "maxLength": 255, + "minLength": 0 + }, + "selectedPlace": { + "$ref": "#/components/schemas/SelectedPlacePayload", + "description": "선택된 장소 정보" + } + }, + "required": ["name", "selectedPlace"] + }, + "PartnerSignUpRequestDTO": { + "type": "object", + "description": "JSON 형식의 제휴업체 가입 정보", + "properties": { + "phoneNumber": { + "type": "string", + "description": "휴대폰 번호", + "example": "01012345678", + "pattern": "^(01[016789])\\d{3,4}\\d{4}$" + }, + "marketingAgree": { + "type": "boolean", + "description": "마케팅 수신 동의", + "example": true + }, + "locationAgree": { + "type": "boolean", + "description": "위치 정보 수집 동의", + "example": true + }, + "commonAuth": { + "$ref": "#/components/schemas/CommonAuthPayloadDTO", + "description": "관리자/제휴업체공통 인증 정보" + }, + "commonInfo": { + "$ref": "#/components/schemas/CommonInfoPayloadDTO", + "description": "관리자/제휴업체 공통 정보" + } + }, + "required": [ + "commonAuth", + "commonInfo", + "locationAgree", + "marketingAgree" + ] + }, + "EmailVerificationCheckRequestDTO": { + "type": "object", + "description": "이메일 중복 확인 요청", + "properties": { + "email": { + "type": "string", + "description": "확인할 이메일 주소", + "example": "user@example.com" + } + }, + "required": ["email"] + }, + "CommonLoginRequestDTO": { + "type": "object", + "description": "파트너/관리자 공통 로그인 요청", + "properties": { + "email": { + "type": "string", + "description": "로그인 이메일", + "example": "user@example.com", + "maxLength": 255, + "minLength": 0 + }, + "password": { + "type": "string", + "description": "로그인 비밀번호(평문)", + "example": "P@ssw0rd!", + "maxLength": 64, + "minLength": 8 + } + }, + "required": ["email", "password"] + }, + "AdminSignUpRequestDTO": { + "type": "object", + "description": "JSON 형식의 관리자 가입 정보", + "properties": { + "phoneNumber": { + "type": "string", + "description": "휴대폰 번호", + "example": "01012345678", + "pattern": "^(01[016789])\\d{3,4}\\d{4}$" + }, + "marketingAgree": { + "type": "boolean", + "description": "마케팅 수신 동의", + "example": true + }, + "locationAgree": { + "type": "boolean", + "description": "위치 정보 수집 동의", + "example": true + }, + "commonAuth": { + "$ref": "#/components/schemas/CommonAuthPayloadDTO", + "description": "관리자/제휴업체공통 인증 정보" + }, + "commonInfo": { + "$ref": "#/components/schemas/CommonInfoPayloadDTO", + "description": "관리자/제휴업체 공통 정보" + } + }, + "required": [ + "commonAuth", + "commonInfo", + "locationAgree", + "marketingAgree" + ] + }, + "AppReviewRequestDTO": { + "type": "object", + "description": "앱 리뷰 작성 요청", + "properties": { + "rate": { + "type": "integer", + "format": "int32", + "description": "별점 (1~5)", + "example": 5, + "maximum": 5, + "minimum": 1 + }, + "content": { + "type": "string", + "description": "후기 내용", + "example": "너무 좋아용~" + } + }, + "required": ["content", "rate"] + }, + "PartnershipStatusUpdateRequestDTO": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "제안서에 적용할 상태 (ACTIVE/SUSPEND/INACTIVE)", + "example": "ACTIVE" + } + }, + "required": ["status"] + }, + "BaseResponsePartnershipStatusUpdateResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PartnershipStatusUpdateResponseDTO" + } + } + }, + "PartnershipStatusUpdateResponseDTO": { + "type": "object", + "properties": { + "partnershipId": { + "type": "integer", + "format": "int64", + "description": "제안서 ID", + "example": 1001 + }, + "prevStatus": { + "type": "string", + "description": "변경 전 제안서 상태", + "example": "SUSPEND" + }, + "newStatus": { + "type": "string", + "description": "변경 후 제안서 상태", + "example": "ACTIVE" + }, + "changedAt": { + "type": "string", + "format": "date-time", + "description": "상태 변경 시간", + "example": "2024-06-15T10:30:00" + } + }, + "required": ["changedAt", "newStatus", "partnershipId", "prevStatus"] + }, + "WritePartnershipRequestDTO": { + "type": "object", + "properties": { + "paperId": { + "type": "integer", + "format": "int64", + "description": "수정할 제안서 ID", + "example": 1001 + }, + "partnershipPeriodStart": { + "type": "string", + "format": "date", + "description": "제휴 시작일", + "example": "2024-01-01" + }, + "partnershipPeriodEnd": { + "type": "string", + "format": "date", + "description": "제휴 마감일", + "example": "2024-12-31" + }, + "options": { + "type": "array", + "description": "제휴 옵션 목록", + "items": { + "$ref": "#/components/schemas/PartnershipOptionRequestDTO" + } + } + }, + "required": [ + "options", + "paperId", + "partnershipPeriodEnd", + "partnershipPeriodStart" + ] + }, + "BaseResponseWritePartnershipResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/WritePartnershipResponseDTO" + } + } + }, + "InquiryAnswerRequestDTO": { + "type": "object", + "properties": { + "answer": { + "type": "string", + "description": "답변 내용", + "example": "안녕하세요. A:SSU 팀입니다." + } + }, + "required": ["answer"] + }, + "BaseResponseReadMessageResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/ReadMessageResponseDTO" + } + } + }, + "ReadMessageResponseDTO": { + "type": "object", + "properties": { + "roomId": { + "type": "integer", + "format": "int64" + }, + "readerId": { + "type": "integer", + "format": "int64" + }, + "readMessagesId": { + "type": "array", + "items": { + "type": "integer", + "format": "int64" + } + }, + "readCount": { + "type": "integer", + "format": "int32" + }, + "isRead": { + "type": "boolean" + } + } + }, + "BaseResponseListTemporaryQrResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TemporaryQrResponseDTO" + } + } + } + }, + "TemporaryQrResponseDTO": { + "type": "object", + "properties": { + "adminName": { + "type": "string" + }, + "sort": { + "type": "string", + "enum": ["REVIEW", "SUGGEST"] + }, + "createdAt": { + "type": "string" + } + } + }, + "BaseResponseListGetSuggestionResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/GetSuggestionResponseDTO" + } + } + } + }, + "GetSuggestionResponseDTO": { + "type": "object", + "properties": { + "suggestionId": { + "type": "integer", + "format": "int64", + "description": "건의 ID", + "example": 1 + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "건의 작성일", + "example": "2026-01-04T12:00:00" + }, + "storeName": { + "type": "string", + "description": "희망 가게 이름", + "example": "스타벅스 숭실대점" + }, + "content": { + "type": "string", + "description": "건의 내용", + "example": "아메리카노 10% 할인" + }, + "studentMajor": { + "type": "string", + "description": "건의자의 학부/학과", + "enum": [ + "CHRISTIAN_STUDIES", + "KOREAN_LITERATURE", + "ENGLISH_LITERATURE", + "GERMAN_LITERATURE", + "FRENCH_LITERATURE", + "CHINESE_LITERATURE", + "JAPANESE_LITERATURE", + "PHILOSOPHY", + "HISTORY", + "CREATIVE_ARTS", + "SPORTS", + "MATHEMATICS", + "CHEMISTRY", + "BIOMEDICAL_SYSTEMS", + "PHYSICS", + "STATISTICS_ACTUARIAL", + "LAW", + "INTERNATIONAL_LAW", + "SOCIAL_WELFARE", + "POLITICAL_SCIENCE", + "MEDIA_COMMUNICATION", + "PUBLIC_ADMINISTRATION", + "INFORMATION_SOCIETY", + "LIFELONG_EDUCATION", + "ECONOMICS", + "FINANCIAL_ECONOMICS", + "GLOBAL_TRADE", + "INTERNATIONAL_TRADE", + "BUSINESS_ADMINISTRATION", + "ACCOUNTING", + "VENTURE_MANAGEMENT", + "WELFARE_MANAGEMENT", + "VENTURE_SME", + "FINANCE", + "INNOVATION_MANAGEMENT", + "ACCOUNTING_TAX", + "CHEMICAL_ENGINEERING", + "ELECTRICAL_ENGINEERING", + "ARCHITECTURE", + "INDUSTRIAL_INFO_SYSTEMS", + "MECHANICAL_ENGINEERING", + "MATERIALS_SCIENCE", + "SOFTWARE", + "GLOBAL_MEDIA", + "COMPUTER_SCIENCE", + "ELECTRONIC_ENGINEERING", + "AI_CONVERGENCE", + "DIGITAL_MEDIA", + "LIBERAL_STUDIES", + "AI_SOFTWARE", + "INFORMATION_SECURITY" + ], + "example": "COM" + }, + "enrollmentStatus": { + "type": "string", + "description": "재학 상태", + "enum": ["ENROLLED", "LEAVE", "GRADUATED"], + "example": "ENROLLED" + } + }, + "required": [ + "content", + "createdAt", + "enrollmentStatus", + "storeName", + "studentMajor", + "suggestionId" + ] + }, + "BaseResponseGetSuggestionAdminsDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/GetSuggestionAdminsDTO" + } + } + }, + "GetSuggestionAdminsDTO": { + "type": "object", + "properties": { + "adminId": { + "type": "integer", + "format": "int64", + "description": "총학생회 ID", + "example": 1 + }, + "adminName": { + "type": "string", + "description": "총학생회 이름", + "example": "숭실대학교 총학생회" + }, + "departId": { + "type": "integer", + "format": "int64", + "description": "단과대학 학생회 ID", + "example": 2 + }, + "departName": { + "type": "string", + "description": "단과대학 학생회 이름", + "example": "IT대학 학생회" + }, + "majorId": { + "type": "integer", + "format": "int64", + "description": "학부/학과 학생회 ID", + "example": 3 + }, + "majorName": { + "type": "string", + "description": "학부/학과 학생회 이름", + "example": "컴퓨터학부 학생회" + } + } + }, + "Pageable": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "format": "int32", + "minimum": 0 + }, + "size": { + "type": "integer", + "format": "int32", + "minimum": 1 + }, + "sort": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "BaseResponsePageUsageDetail": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PageUsageDetail" + } + } + }, + "PageUsageDetail": { + "type": "object", + "properties": { + "totalPages": { + "type": "integer", + "format": "int32" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UsageDetail" + } + }, + "number": { + "type": "integer", + "format": "int32" + }, + "sort": { + "$ref": "#/components/schemas/SortObject" + }, + "first": { + "type": "boolean" + }, + "last": { + "type": "boolean" + }, + "pageable": { + "$ref": "#/components/schemas/PageableObject" + }, + "numberOfElements": { + "type": "integer", + "format": "int32" + }, + "empty": { + "type": "boolean" + } + } + }, + "PageableObject": { + "type": "object", + "properties": { + "offset": { + "type": "integer", + "format": "int64" + }, + "sort": { + "$ref": "#/components/schemas/SortObject" + }, + "paged": { + "type": "boolean" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "pageNumber": { + "type": "integer", + "format": "int32" + }, + "unpaged": { + "type": "boolean" + } + } + }, + "SortObject": { + "type": "object", + "properties": { + "empty": { + "type": "boolean" + }, + "unsorted": { + "type": "boolean" + }, + "sorted": { + "type": "boolean" + } + } + }, + "UsageDetail": { + "type": "object", + "properties": { + "adminName": { + "type": "string" + }, + "partnershipUsageId": { + "type": "integer", + "format": "int64" + }, + "storeName": { + "type": "string" + }, + "partnerId": { + "type": "integer", + "format": "int64" + }, + "storeId": { + "type": "integer", + "format": "int64" + }, + "usedAt": { + "type": "string" + }, + "benefitDescription": { + "type": "string" + }, + "isReviewed": { + "type": "boolean" + } + } + }, + "BaseResponseListUsablePartnershipDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UsablePartnershipDTO" + } + } + } + }, + "UsablePartnershipDTO": { + "type": "object", + "properties": { + "partnershipId": { + "type": "integer", + "format": "int64" + }, + "adminName": { + "type": "string" + }, + "partnerName": { + "type": "string" + }, + "criterionType": { + "type": "string", + "enum": ["PRICE", "HEADCOUNT"] + }, + "optionType": { + "type": "string", + "enum": ["SERVICE", "DISCOUNT"] + }, + "people": { + "type": "integer", + "format": "int32" + }, + "cost": { + "type": "integer", + "format": "int64" + }, + "note": { + "type": "string" + }, + "paperId": { + "type": "integer", + "format": "int64" + }, + "category": { + "type": "string" + }, + "discountRate": { + "type": "integer", + "format": "int64" + } + } + }, + "BaseResponseCheckStampResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CheckStampResponseDTO" + } + } + }, + "CheckStampResponseDTO": { + "type": "object", + "properties": { + "userId": { + "type": "integer", + "format": "int64" + }, + "stamp": { + "type": "integer", + "format": "int32" + }, + "message": { + "type": "string" + } + } + }, + "BaseResponseMyPartnership": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/MyPartnership" + } + } + }, + "MyPartnership": { + "type": "object", + "properties": { + "serviceCount": { + "type": "integer", + "format": "int64" + }, + "details": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UsageDetail" + } + } + } + }, + "BaseResponsePaperResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PaperResponseDTO" + } + } + }, + "PaperContentResponseDTO": { + "type": "object", + "properties": { + "adminId": { + "type": "integer", + "format": "int64" + }, + "adminName": { + "type": "string" + }, + "paperContent": { + "type": "string" + }, + "contentId": { + "type": "integer", + "format": "int64" + }, + "goods": { + "type": "array", + "items": { + "type": "string" + } + }, + "people": { + "type": "integer", + "format": "int32" + }, + "cost": { + "type": "integer", + "format": "int64" + } + } + }, + "PaperResponseDTO": { + "type": "object", + "properties": { + "partnershipContents": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaperContentResponseDTO" + } + }, + "storeName": { + "type": "string" + }, + "storeId": { + "type": "integer", + "format": "int64" + } + } + }, + "BaseResponseStampRankingListDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/StampRankingListDTO" + } + } + }, + "StampRankingDTO": { + "type": "object", + "properties": { + "storeId": { + "type": "integer", + "format": "int64" + }, + "storeName": { + "type": "string" + }, + "stampCount": { + "type": "integer", + "format": "int64" + } + } + }, + "StampRankingListDTO": { + "type": "object", + "properties": { + "rankings": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StampRankingDTO" + } + } + } + }, + "BaseResponseWeeklyRankResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/WeeklyRankResponseDTO" + } + } + }, + "WeeklyRankResponseDTO": { + "type": "object", + "properties": { + "rank": { + "type": "integer", + "format": "int64" + }, + "usageCount": { + "type": "integer", + "format": "int64" + } + } + }, + "BaseResponseListWeeklyRankResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WeeklyRankResponseDTO" + } + } + } + }, + "BaseResponseTodayBestResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/TodayBestResponseDTO" + } + } + }, + "TodayBestResponseDTO": { + "type": "object", + "properties": { + "bestStores": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "BaseResponsePageCheckReviewResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PageCheckReviewResponseDTO" + } + } + }, + "CheckReviewResponseDTO": { + "type": "object", + "properties": { + "reviewId": { + "type": "integer", + "format": "int64" + }, + "storeId": { + "type": "integer", + "format": "int64" + }, + "affiliation": { + "type": "string" + }, + "storeName": { + "type": "string" + }, + "content": { + "type": "string" + }, + "rate": { + "type": "integer", + "format": "int32" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "reviewImageUrls": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PageCheckReviewResponseDTO": { + "type": "object", + "properties": { + "totalPages": { + "type": "integer", + "format": "int32" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CheckReviewResponseDTO" + } + }, + "number": { + "type": "integer", + "format": "int32" + }, + "sort": { + "$ref": "#/components/schemas/SortObject" + }, + "first": { + "type": "boolean" + }, + "last": { + "type": "boolean" + }, + "pageable": { + "$ref": "#/components/schemas/PageableObject" + }, + "numberOfElements": { + "type": "integer", + "format": "int32" + }, + "empty": { + "type": "boolean" + } + } + }, + "BaseResponseStandardScoreResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/StandardScoreResponseDTO" + } + } + }, + "StandardScoreResponseDTO": { + "type": "object", + "properties": { + "score": { + "type": "number", + "format": "float" + } + } + }, + "BaseResponsePartnershipDetailResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PartnershipDetailResponseDTO" + } + } + }, + "PartnershipDetailResponseDTO": { + "type": "object", + "properties": { + "partnershipId": { + "type": "integer", + "format": "int64", + "description": "제안서 ID", + "example": 1001 + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "제안서 최종 수정 시간", + "example": "2024-06-15T10:30:00" + }, + "partnershipPeriodStart": { + "type": "string", + "format": "date", + "description": "제휴 시작일", + "example": "2024-01-01" + }, + "partnershipPeriodEnd": { + "type": "string", + "format": "date", + "description": "제휴 마감일", + "example": "2024-12-31" + }, + "adminId": { + "type": "integer", + "format": "int64", + "description": "관리자 ID", + "example": 101 + }, + "partnerId": { + "type": "integer", + "format": "int64", + "description": "제휴업체 ID", + "example": 201 + }, + "storeId": { + "type": "integer", + "format": "int64", + "description": "가게 ID", + "example": 301 + }, + "options": { + "type": "array", + "description": "제휴 옵션 목록", + "items": { + "$ref": "#/components/schemas/PartnershipOptionResponseDTO" + } + } + }, + "required": [ + "adminId", + "options", + "partnershipId", + "partnershipPeriodEnd", + "partnershipPeriodStart", + "storeId", + "updatedAt" + ] + }, + "BaseResponseListSuspendedPaperResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SuspendedPaperResponseDTO" + } + } + } + }, + "SuspendedPaperResponseDTO": { + "type": "object", + "properties": { + "paperId": { + "type": "integer", + "format": "int64", + "description": "제안서 ID", + "example": 1001 + }, + "partnerName": { + "type": "string", + "description": "제휴업체 이름", + "example": "역전할머니맥주 숭실대점" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "제안서 생성 일자", + "example": "2024-01-01T09:00:00" + } + }, + "required": ["createdAt", "paperId", "partnerName"] + }, + "BaseResponsePageWritePartnershipResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PageWritePartnershipResponseDTO" + } + } + }, + "PageWritePartnershipResponseDTO": { + "type": "object", + "properties": { + "totalPages": { + "type": "integer", + "format": "int32" + }, + "totalElements": { + "type": "integer", + "format": "int64" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WritePartnershipResponseDTO" + } + }, + "number": { + "type": "integer", + "format": "int32" + }, + "sort": { + "$ref": "#/components/schemas/SortObject" + }, + "first": { + "type": "boolean" + }, + "last": { + "type": "boolean" + }, + "pageable": { + "$ref": "#/components/schemas/PageableObject" + }, + "numberOfElements": { + "type": "integer", + "format": "int32" + }, + "empty": { + "type": "boolean" + } + } + }, + "BaseResponsePartnerPartnershipCheckResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PartnerPartnershipCheckResponseDTO" + } + } + }, + "PartnerPartnershipCheckResponseDTO": { + "type": "object", + "properties": { + "paperId": { + "type": "integer", + "format": "int64", + "description": "제안서 ID", + "example": 1001 + }, + "isPartnered": { + "type": "boolean", + "description": "제휴 여부", + "example": true + }, + "status": { + "type": "string", + "description": "제휴 상태", + "example": "ACTIVE" + }, + "adminId": { + "type": "integer", + "format": "int64", + "description": "관리자 ID", + "example": 101 + }, + "adminName": { + "type": "string", + "description": "관리자 이름", + "example": "숭실대학교 총학생회" + }, + "adminAddress": { + "type": "string", + "description": "관리자 주소", + "example": "서울특별시 동작구 상도로" + } + }, + "required": [ + "adminAddress", + "adminId", + "adminName", + "paperId", + "status" + ] + }, + "AdminPartnershipCheckResponseDTO": { + "type": "object", + "properties": { + "paperId": { + "type": "integer", + "format": "int64", + "description": "제안서 ID", + "example": 1001 + }, + "isPartnered": { + "type": "boolean", + "description": "제휴 여부", + "example": true + }, + "status": { + "type": "string", + "description": "제휴 상태", + "example": "ACTIVE" + }, + "partnerId": { + "type": "integer", + "format": "int64", + "description": "제휴업체 ID", + "example": 201 + }, + "partnerName": { + "type": "string", + "description": "제휴업체 이름", + "example": "역전할머니맥주 숭실대점" + }, + "partnerAddress": { + "type": "string", + "description": "제휴업체 주소", + "example": "서울특별시 동작구 상도로" + } + } + }, + "BaseResponseAdminPartnershipCheckResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/AdminPartnershipCheckResponseDTO" + } + } + }, + "AdminLiteDTO": { + "type": "object", + "properties": { + "adminId": { + "type": "integer", + "format": "int64" + }, + "adminAddress": { + "type": "string" + }, + "adminDetailAddress": { + "type": "string" + }, + "adminName": { + "type": "string" + }, + "adminUrl": { + "type": "string" + }, + "adminPhone": { + "type": "string" + } + } + }, + "BaseResponsePartnerResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PartnerResponseDTO" + } + } + }, + "PartnerResponseDTO": { + "type": "object", + "properties": { + "admins": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AdminLiteDTO" + } + } + } + }, + "BaseResponseMapStringObject": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + }, + "BaseResponseBoolean": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "boolean" + } + } + }, + "BaseResponseObject": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "object" + } + } + }, + "BaseResponseListPlaceSuggestionDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PlaceSuggestionDTO" + } + } + } + }, + "PlaceSuggestionDTO": { + "type": "object", + "properties": { + "placeId": { + "type": "string", + "description": "장소 ID", + "example": 12345678 + }, + "name": { + "type": "string", + "description": "장소 이름", + "example": "숭실대학교" + }, + "category": { + "type": "string", + "description": "장소 카테고리", + "example": "대학교" + }, + "address": { + "type": "string", + "description": "장소 지번 주소", + "example": "서울특별시 동작구 상도로 369" + }, + "roadAddress": { + "type": "string", + "description": "장소 도로명 주소", + "example": "서울특별시 동작구 상도로 369" + }, + "phone": { + "type": "string", + "description": "장소 전화번호", + "example": "02-820-0114" + }, + "placeUrl": { + "type": "string", + "description": "카카오맵 장소 Url", + "example": "https://place.map.kakao.com/12345678" + }, + "latitude": { + "type": "number", + "format": "double", + "description": "장소 위도", + "example": 37.5 + }, + "longitude": { + "type": "number", + "format": "double", + "description": "장소 경도", + "example": 126.96 + }, + "distance": { + "type": "integer", + "format": "int32", + "description": "현재 위치로부터의 거리 (m)", + "example": 100 + } + } + }, + "MapRequestDTO": { + "type": "object", + "properties": { + "lng1": { + "type": "number", + "format": "double", + "description": "화면 좌상단 경도", + "example": 126.95 + }, + "lat1": { + "type": "number", + "format": "double", + "description": "화면 좌상단 위도", + "example": 37.51 + }, + "lng2": { + "type": "number", + "format": "double", + "description": "화면 우상단 경도", + "example": 126.97 + }, + "lat2": { + "type": "number", + "format": "double", + "description": "화면 우상단 위도", + "example": 37.51 + }, + "lng3": { + "type": "number", + "format": "double", + "description": "화면 우하단 경도", + "example": 126.97 + }, + "lat3": { + "type": "number", + "format": "double", + "description": "화면 우하단 위도", + "example": 37.49 + }, + "lng4": { + "type": "number", + "format": "double", + "description": "화면 좌하단 경도", + "example": 126.95 + }, + "lat4": { + "type": "number", + "format": "double", + "description": "화면 좌하단 위도", + "example": 37.49 + } + }, + "required": [ + "lat1", + "lat2", + "lat3", + "lat4", + "lng1", + "lng2", + "lng3", + "lng4" + ] + }, + "BaseResponsePageResponseDTOInquiryResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/PageResponseDTOInquiryResponseDTO" + } + } + }, + "InquiryResponseDTO": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64", + "description": "문의 ID", + "example": 12 + }, + "title": { + "type": "string", + "description": "문의 제목", + "example": "상호명 변경 요청드립니다." + }, + "content": { + "type": "string", + "description": "문의 내용", + "example": "안녕하세요. 역할맥입니다. 상호명을 변경하고 싶습니다." + }, + "email": { + "type": "string", + "description": "문의자 이메일", + "example": "assu@gmail.com" + }, + "status": { + "type": "string", + "description": "문의 상태", + "example": "WAITING, ANSWERED, ALL" + }, + "answer": { + "type": "string", + "description": "답변 내용", + "example": "안녕하세요. A:SSU 팀입니다." + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "문의 생성 일시", + "example": "2026-01-20T14:30:00" + } + } + }, + "PageResponseDTOInquiryResponseDTO": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/InquiryResponseDTO" + } + }, + "page": { + "type": "integer", + "format": "int32" + }, + "size": { + "type": "integer", + "format": "int32" + }, + "totalPages": { + "type": "integer", + "format": "int32" + }, + "totalElements": { + "type": "integer", + "format": "int64" + } + } + }, + "BaseResponseInquiryResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/InquiryResponseDTO" + } + } + }, + "BaseResponseListChatRoomListResultDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatRoomListResultDTO" + } + } + } + }, + "ChatRoomListResultDTO": { + "type": "object", + "properties": { + "roomId": { + "type": "integer", + "format": "int64" + }, + "lastMessage": { + "type": "string" + }, + "lastMessageTime": { + "type": "string", + "format": "date-time" + }, + "unreadMessagesCount": { + "type": "integer", + "format": "int64" + }, + "opponentId": { + "type": "integer", + "format": "int64" + }, + "opponentName": { + "type": "string" + }, + "opponentProfileImage": { + "type": "string" + }, + "phoneNumber": { + "type": "string" + } + } + }, + "BaseResponseChatHistoryResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/ChatHistoryResponseDTO" + } + } + }, + "ChatHistoryResponseDTO": { + "type": "object", + "properties": { + "roomId": { + "type": "integer", + "format": "int64" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ChatMessageDTO" + } + } + } + }, + "ChatMessageDTO": { + "type": "object", + "properties": { + "messageId": { + "type": "integer", + "format": "int64" + }, + "message": { + "type": "string" + }, + "sendTime": { + "type": "string", + "format": "date-time" + }, + "unreadCountForSender": { + "type": "integer", + "format": "int32" + }, + "isRead": { + "type": "boolean" + }, + "isMyMessage": { + "type": "boolean" + }, + "messageType": { + "type": "string", + "enum": ["TEXT", "PROPOSAL", "SYSTEM", "GUIDE"] + } + } + }, + "BaseResponseCheckBlockMemberDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CheckBlockMemberDTO" + } + } + }, + "CheckBlockMemberDTO": { + "type": "object", + "properties": { + "memberId": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "blocked": { + "type": "boolean" + } + } + }, + "BaseResponseListBlockMemberDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BlockMemberDTO" + } + } + } + }, + "AdminResponseDTO": { + "type": "object", + "properties": { + "partnerId": { + "type": "integer", + "format": "int64", + "description": "제휴업체 ID", + "example": 101 + }, + "partnerName": { + "type": "string", + "description": "제휴업체 이름", + "example": "역전할머니 맥주 숭실대점" + }, + "partnerAddress": { + "type": "string", + "description": "제휴업체 주소", + "example": "서울특별시 동작구" + }, + "partnerDetailAddress": { + "type": "string", + "description": "제휴업체 상세주소", + "example": "2층 201호" + }, + "partnerUrl": { + "type": "string", + "description": "제휴업체 URL", + "example": "https://www.beer.co.kr" + }, + "partnerPhone": { + "type": "string", + "description": "제휴업체 전화번호", + "example": "02-123-4567" + } + }, + "required": ["partnerAddress", "partnerId", "partnerName"] + }, + "BaseResponseAdminResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/AdminResponseDTO" + } + } + }, + "BaseResponseCountAdminAuthResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CountAdminAuthResponseDTO" + } + } + }, + "CountAdminAuthResponseDTO": { + "type": "object", + "properties": { + "studentCount": { + "type": "integer", + "format": "int64" + }, + "adminId": { + "type": "integer", + "format": "int64" + }, + "adminName": { + "type": "string" + } + } + }, + "BaseResponseCountUsageListResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CountUsageListResponseDTO" + } + } + }, + "CountUsageListResponseDTO": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CountUsageResponseDTO" + } + } + } + }, + "CountUsageResponseDTO": { + "type": "object", + "properties": { + "usageCount": { + "type": "integer", + "format": "int64" + }, + "adminId": { + "type": "integer", + "format": "int64" + }, + "adminName": { + "type": "string" + }, + "storeId": { + "type": "integer", + "format": "int64" + }, + "storeName": { + "type": "string" + } + } + }, + "BaseResponseCountUsageResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CountUsageResponseDTO" + } + } + }, + "BaseResponseNewCountAdminResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/NewCountAdminResponseDTO" + } + } + }, + "NewCountAdminResponseDTO": { + "type": "object", + "properties": { + "newStudentCount": { + "type": "integer", + "format": "int64" + }, + "adminId": { + "type": "integer", + "format": "int64" + }, + "adminName": { + "type": "string" + } + } + }, + "BaseResponseCountUsagePersonResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/CountUsagePersonResponseDTO" + } + } + }, + "CountUsagePersonResponseDTO": { + "type": "object", + "properties": { + "usagePersonCount": { + "type": "integer", + "format": "int64" + }, + "adminId": { + "type": "integer", + "format": "int64" + }, + "adminName": { + "type": "string" + } + } + }, + "BaseResponseDeleteReviewResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/DeleteReviewResponseDTO" + } + } + }, + "DeleteReviewResponseDTO": { + "type": "object", + "properties": { + "reviewId": { + "type": "integer", + "format": "int64" + } + } + }, + "BaseResponseLeaveChattingRoomResponseDTO": { + "type": "object", + "properties": { + "isSuccess": { + "type": "boolean" + }, + "code": { + "type": "string" + }, + "message": { + "type": "string" + }, + "result": { + "$ref": "#/components/schemas/LeaveChattingRoomResponseDTO" + } + } + }, + "LeaveChattingRoomResponseDTO": { + "type": "object", + "properties": { + "roomId": { + "type": "integer", + "format": "int64" + }, + "isLeftSuccessfully": { + "type": "boolean" + }, + "isRoomDeleted": { + "type": "boolean" + } + } + } + }, + "securitySchemes": { + "JWT TOKEN": { + "type": "http", + "name": "JWT TOKEN", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } +} diff --git a/src/app/(protected)/admin/map-search.tsx b/src/app/(protected)/admin/map-search.tsx new file mode 100644 index 0000000..d157a1b --- /dev/null +++ b/src/app/(protected)/admin/map-search.tsx @@ -0,0 +1,5 @@ +import { MapSearchPage } from "@/pages/map-search"; + +export default function AdminMapSearchScreen() { + return ; +} diff --git a/src/app/(protected)/partner/map-search.tsx b/src/app/(protected)/partner/map-search.tsx new file mode 100644 index 0000000..e636a5d --- /dev/null +++ b/src/app/(protected)/partner/map-search.tsx @@ -0,0 +1,5 @@ +import { MapSearchPage } from "@/pages/map-search"; + +export default function PartnerMapSearchScreen() { + return ; +} diff --git a/src/app/(protected)/student/map-search.tsx b/src/app/(protected)/student/map-search.tsx new file mode 100644 index 0000000..3cd4b32 --- /dev/null +++ b/src/app/(protected)/student/map-search.tsx @@ -0,0 +1,5 @@ +import { MapSearchPage } from "@/pages/map-search"; + +export default function StudentMapSearchScreen() { + return ; +} diff --git a/src/entities/store/index.ts b/src/entities/store/index.ts new file mode 100644 index 0000000..ce00438 --- /dev/null +++ b/src/entities/store/index.ts @@ -0,0 +1,8 @@ +export type { + AdminStoreCardData, + PopularStore, + SearchResultStore, + Store, + StoreMarker, + StudentStoreCardData, +} from "./model/types"; diff --git a/src/entities/store/model/types.ts b/src/entities/store/model/types.ts new file mode 100644 index 0000000..6dd6fc1 --- /dev/null +++ b/src/entities/store/model/types.ts @@ -0,0 +1,46 @@ +export interface Store { + id: string; + name: string; + address: string; + latitude: number; + longitude: number; +} + +export interface StoreMarker extends Store { + count?: number; +} + +export interface StudentStoreCardData extends Store { + imageUri?: string; + rating: number; + reviewCount: number; + priceRange?: string; +} + +export interface AdminStoreCardData extends Store { + imageUri?: string; + partnershipStartDate?: string; + partnershipEndDate?: string; + isPartner: boolean; +} + +export interface PopularStore { + id: string; + name: string; + category?: string; +} + +export interface SearchResultStore { + id: string; + name: string; + imageUri?: string; + // student view + tag?: string; + benefit?: string; + // admin / partner view + address?: string; + // partner-specific + isPartner?: boolean; + partnershipStartDate?: string; + partnershipEndDate?: string; +} diff --git a/src/features/map-search/index.ts b/src/features/map-search/index.ts new file mode 100644 index 0000000..7150301 --- /dev/null +++ b/src/features/map-search/index.ts @@ -0,0 +1 @@ +export { usePopularStores, useSearchStores } from "./model/useMapSearch"; diff --git a/src/features/map-search/model/useMapSearch.ts b/src/features/map-search/model/useMapSearch.ts new file mode 100644 index 0000000..b0b822a --- /dev/null +++ b/src/features/map-search/model/useMapSearch.ts @@ -0,0 +1,129 @@ +import { useQuery } from "@tanstack/react-query"; + +import type { PopularStore, SearchResultStore } from "@/entities/store"; + +const MOCK_POPULAR_STORES: PopularStore[] = [ + { id: "1", name: "역전할머니맥주" }, + { id: "2", name: "취향" }, + { id: "3", name: "Bread & co" }, + { id: "4", name: "인쌩맥주" }, + { id: "5", name: "리얼후라이" }, + { id: "6", name: "이자카야 젠" }, + { id: "7", name: "상도로 3가" }, + { id: "8", name: "인쌩맥주" }, +]; + +const MOCK_SEARCH_STORES: SearchResultStore[] = [ + { + id: "1", + name: "역전할머니맥주 숭실대점", + tag: "IT대 학생회", + benefit: "4인이상 식사시, 음료제공", + address: "서울 동작구 상도로 369", + isPartner: true, + partnershipStartDate: "2025.02.24", + partnershipEndDate: "2025.06.15", + }, + { + id: "2", + name: "취향", + tag: "총학생회", + benefit: "4인이상 식사시, 음료제공", + address: "서울 동작구 사당로 36-1", + isPartner: true, + partnershipStartDate: "2025.03.01", + partnershipEndDate: "2025.08.31", + }, + { + id: "3", + name: "Bread & co", + tag: "공대 학생회", + benefit: "음료 10% 할인", + address: "서울 동작구 상도로 312", + isPartner: false, + }, + { + id: "4", + name: "인쌩맥주", + tag: "생활관", + benefit: "빵 구매 시 아메리카노 제공", + address: "서울 동작구 상도로 407", + isPartner: true, + partnershipStartDate: "2025.01.15", + partnershipEndDate: "2025.07.14", + }, + { + id: "5", + name: "리얼후라이", + tag: "총학생회", + benefit: "세트 메뉴 10% 할인", + address: "서울 동작구 상도로 391", + isPartner: false, + }, + { + id: "6", + name: "이자카야 젠", + tag: "IT대 학생회", + benefit: "2인 이상 방문 시 음료 1잔 제공", + address: "서울 동작구 사당로 34", + isPartner: false, + }, + { + id: "7", + name: "상도로 3가", + tag: "생활관", + benefit: "식사 후 음료 50% 할인", + address: "서울 동작구 상도로 298", + isPartner: true, + partnershipStartDate: "2025.04.01", + partnershipEndDate: "2025.09.30", + }, + { + id: "8", + name: "역전 테스트", + tag: "IT대 학생회", + benefit: "테스트용 혜택입니다", + address: "서울 동작구 상도로 99", + isPartner: false, + }, +]; + +const fetchPopularStores = async (): Promise => { + // TODO: replace with actual API call + // return apiClient.get("/stores/popular").then(res => res.data); + return new Promise((resolve) => { + setTimeout(() => resolve(MOCK_POPULAR_STORES), 300); + }); +}; + +const fetchSearchStores = async ( + query: string, +): Promise => { + // TODO: replace with actual API call + // return apiClient.get("/stores/search", { params: { q: query } }).then(res => res.data); + return new Promise((resolve) => { + setTimeout(() => { + const results = MOCK_SEARCH_STORES.filter((store) => + store.name.toLowerCase().includes(query.toLowerCase()), + ); + resolve(results); + }, 300); + }); +}; + +export function usePopularStores() { + return useQuery({ + queryKey: ["popularStores"], + queryFn: fetchPopularStores, + staleTime: 1000 * 60 * 5, + }); +} + +export function useSearchStores(query: string) { + return useQuery({ + queryKey: ["storeSearch", query], + queryFn: () => fetchSearchStores(query), + enabled: query.trim().length > 0, + staleTime: 1000 * 60, + }); +} diff --git a/src/pages/admin/admin-partnership-list/ui/PartnerListPage.tsx b/src/pages/admin/admin-partnership-list/ui/PartnerListPage.tsx index 00a5131..77bcb7e 100644 --- a/src/pages/admin/admin-partnership-list/ui/PartnerListPage.tsx +++ b/src/pages/admin/admin-partnership-list/ui/PartnerListPage.tsx @@ -75,7 +75,7 @@ export function PartnerListPage() { onQrPress={() => { if (selectedContractId) { router.push({ - pathname: "/qr-view/[id]", + pathname: "/(protected)/qr-view/[id]", params: { id: selectedContractId }, }); } diff --git a/src/pages/admin/map/ui/AdminMapPage.tsx b/src/pages/admin/map/ui/AdminMapPage.tsx index 8ae7a1a..12b1151 100644 --- a/src/pages/admin/map/ui/AdminMapPage.tsx +++ b/src/pages/admin/map/ui/AdminMapPage.tsx @@ -1,9 +1,15 @@ -import { Text, View } from "react-native"; +import { router } from "expo-router"; +import { View } from "react-native"; + +import { MapSearchBar, MapView } from "@/widgets/map"; export function AdminMapPage() { return ( - - 관리자 맵 + + + router.push("/(protected)/admin/map-search")} + /> ); } diff --git a/src/pages/map-search/index.ts b/src/pages/map-search/index.ts new file mode 100644 index 0000000..3b41b00 --- /dev/null +++ b/src/pages/map-search/index.ts @@ -0,0 +1 @@ +export { MapSearchPage } from "./ui/MapSearchPage"; diff --git a/src/pages/map-search/ui/MapSearchPage.tsx b/src/pages/map-search/ui/MapSearchPage.tsx new file mode 100644 index 0000000..d9085b5 --- /dev/null +++ b/src/pages/map-search/ui/MapSearchPage.tsx @@ -0,0 +1,159 @@ +import { useRouter } from "expo-router"; +import { useRef, useState } from "react"; +import { + FlatList, + Pressable, + StyleSheet, + Text, + TextInput, + View, +} from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; + +import type { PopularStore, SearchResultStore } from "@/entities/store"; +import { usePopularStores, useSearchStores } from "@/features/map-search"; +import { BackArrowIcon, CloseIcon, LocationIcon } from "@/shared/assets/icons"; +import { useDebounce } from "@/shared/lib/hooks/useDebounce"; +import { shadows } from "@/shared/styles/shadows"; +import { colorTokens } from "@/shared/styles/tokens"; +import { SearchResultCard } from "@/widgets/map"; + +type Role = "student" | "admin" | "partner"; + +interface MapSearchPageProps { + userRole: Role; +} + +export function MapSearchPage({ userRole: role }: MapSearchPageProps) { + const router = useRouter(); + const insets = useSafeAreaInsets(); + const inputRef = useRef(null); + const [query, setQuery] = useState(""); + const debouncedQuery = useDebounce(query, 300); + + const isSearching = debouncedQuery.trim().length > 0; + const showPopular = !isSearching && role !== "partner"; + + const { data: popularStores = [] } = usePopularStores(); + const { data: searchResults = [], isLoading: isSearchLoading } = + useSearchStores(debouncedQuery.trim()); + + return ( + + + router.back()} hitSlop={8}> + + + + + + {query.length > 0 && ( + setQuery("")} hitSlop={8}> + + + )} + + + + {isSearching ? ( + !isSearchLoading && searchResults.length === 0 ? ( + + + 검색결과를 찾지 못했어요! + + + { + "매장을 찾지 못해 페이지를 표시할 수 없어요.\n이용에 불편을 드려 죄송합니다." + } + + + ) : !isSearchLoading && searchResults.length > 0 ? ( + item.id} + renderItem={({ item }: { item: SearchResultStore }) => ( + + )} + ItemSeparatorComponent={SearchResultSeparator} + ListHeaderComponent={ + + {searchResults.length}개의 검색 결과가 있습니다 + + } + contentContainerStyle={{ paddingHorizontal: 14 }} + /> + ) : null + ) : ( + showPopular && + popularStores.length > 0 && ( + + + {"🔥 지금 많이 찾는 "} + 제휴 + {" 매장"} + + + {popularStores.map((store, index) => ( + setQuery(store.name)} + /> + ))} + + + ) + )} + + ); +} + +function SearchResultSeparator() { + return ( + + + + ); +} + +function PopularStoreRow({ + store, + rank, + onPress, +}: { + store: PopularStore; + rank: number; + onPress: () => void; +}) { + return ( + + + {rank} + + + {store.name} + + + ); +} diff --git a/src/pages/partner/map/ui/PartnerMapPage.tsx b/src/pages/partner/map/ui/PartnerMapPage.tsx index e6d7108..4e6ce87 100644 --- a/src/pages/partner/map/ui/PartnerMapPage.tsx +++ b/src/pages/partner/map/ui/PartnerMapPage.tsx @@ -1,9 +1,15 @@ -import { Text, View } from "react-native"; +import { router } from "expo-router"; +import { View } from "react-native"; + +import { MapSearchBar, MapView } from "@/widgets/map"; export function PartnerMapPage() { return ( - - 제휴업체 맵 + + + router.push("/(protected)/partner/map-search")} + /> ); } diff --git a/src/pages/partner/partner-partnership-list/ui/PartnershipListPage.tsx b/src/pages/partner/partner-partnership-list/ui/PartnershipListPage.tsx index 04da834..b7af3d7 100644 --- a/src/pages/partner/partner-partnership-list/ui/PartnershipListPage.tsx +++ b/src/pages/partner/partner-partnership-list/ui/PartnershipListPage.tsx @@ -75,7 +75,7 @@ export function PartnershipListPage() { onQrPress={() => { if (selectedContractId) { router.push({ - pathname: "/qr-view/[id]", + pathname: "/(protected)/qr-view/[id]", params: { id: selectedContractId }, }); } diff --git a/src/pages/partnership-contract/ui/PartnershipContractPage.tsx b/src/pages/partnership-contract/ui/PartnershipContractPage.tsx index 6a72663..3c52aff 100644 --- a/src/pages/partnership-contract/ui/PartnershipContractPage.tsx +++ b/src/pages/partnership-contract/ui/PartnershipContractPage.tsx @@ -24,7 +24,7 @@ export function PartnershipContractPage() { onClose={() => router.back()} onQrPress={() => router.push({ - pathname: "/qr-view/[id]", + pathname: "/(protected)/qr-view/[id]", params: { id: contract.id }, }) } diff --git a/src/pages/partnership-proposal/ui/PartnershipProposalPage.tsx b/src/pages/partnership-proposal/ui/PartnershipProposalPage.tsx index 1a2f3b5..7753b26 100644 --- a/src/pages/partnership-proposal/ui/PartnershipProposalPage.tsx +++ b/src/pages/partnership-proposal/ui/PartnershipProposalPage.tsx @@ -12,7 +12,6 @@ import { proposalSchema, } from "@/features/partnership-proposal"; import { AppTopBar } from "@/shared/ui/app-top-bar"; -import { PageLayout } from "@/shared/ui/layout"; type Step = "step1" | "step2" | "complete"; diff --git a/src/pages/student/map/ui/StudentMapPage.tsx b/src/pages/student/map/ui/StudentMapPage.tsx index 4105b5b..fadf603 100644 --- a/src/pages/student/map/ui/StudentMapPage.tsx +++ b/src/pages/student/map/ui/StudentMapPage.tsx @@ -1,9 +1,15 @@ -import { Text, View } from "react-native"; +import { router } from "expo-router"; +import { View } from "react-native"; + +import { MapSearchBar, MapView } from "@/widgets/map"; export function StudentMapPage() { return ( - - 학생 맵 + + + router.push("/(protected)/student/map-search")} + /> ); } diff --git a/src/shared/assets/icons/location.svg b/src/shared/assets/icons/location.svg new file mode 100644 index 0000000..3781353 --- /dev/null +++ b/src/shared/assets/icons/location.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/shared/lib/hooks/useDebounce.ts b/src/shared/lib/hooks/useDebounce.ts new file mode 100644 index 0000000..e059794 --- /dev/null +++ b/src/shared/lib/hooks/useDebounce.ts @@ -0,0 +1,12 @@ +import { useEffect, useState } from "react"; + +export function useDebounce(value: T, delay = 300): T { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const timer = setTimeout(() => setDebouncedValue(value), delay); + return () => clearTimeout(timer); + }, [value, delay]); + + return debouncedValue; +} diff --git a/src/shared/ui/summary-card/SummaryCard.tsx b/src/shared/ui/summary-card/SummaryCard.tsx index b40faf2..f343964 100644 --- a/src/shared/ui/summary-card/SummaryCard.tsx +++ b/src/shared/ui/summary-card/SummaryCard.tsx @@ -69,7 +69,7 @@ export const SummaryCard = memo( {actionLabel ? ( diff --git a/src/widgets/map/index.ts b/src/widgets/map/index.ts new file mode 100644 index 0000000..7b14e6e --- /dev/null +++ b/src/widgets/map/index.ts @@ -0,0 +1,7 @@ +export { + AdminStoreCard, + MapSearchBar, + MapView, + SearchResultCard, + StudentStoreCard, +} from "./ui"; diff --git a/src/widgets/map/ui/AdminStoreCard.tsx b/src/widgets/map/ui/AdminStoreCard.tsx new file mode 100644 index 0000000..71d0669 --- /dev/null +++ b/src/widgets/map/ui/AdminStoreCard.tsx @@ -0,0 +1,83 @@ +import { Image, Pressable, Text, View } from "react-native"; + +import type { SearchResultStore } from "@/entities/store"; + +interface AdminStoreCardProps { + store: SearchResultStore; + onActionPress?: () => void; +} + +export function AdminStoreCard({ store, onActionPress }: AdminStoreCardProps) { + const isPartner = store.isPartner ?? false; + const dateRange = + isPartner && store.partnershipStartDate && store.partnershipEndDate + ? `${store.partnershipStartDate} ~ ${store.partnershipEndDate}` + : undefined; + + return ( + + + + {/* Title + status/address */} + + + {store.name} + + {isPartner ? ( + + + + 제휴중 + + + {dateRange && ( + + {dateRange} + + )} + + ) : store.address ? ( + + {store.address} + + ) : null} + + + {/* Action button */} + + + {isPartner ? "제휴 계약서 보기" : "문의하기"} + + + + + ); +} + +function StoreImage({ uri }: { uri?: string }) { + return ( + + {uri ? ( + + ) : null} + + ); +} diff --git a/src/widgets/map/ui/MapSearchBar.tsx b/src/widgets/map/ui/MapSearchBar.tsx new file mode 100644 index 0000000..298fcfb --- /dev/null +++ b/src/widgets/map/ui/MapSearchBar.tsx @@ -0,0 +1,34 @@ +import { Pressable, Text, View } from "react-native"; +import { useSafeAreaInsets } from "react-native-safe-area-context"; + +import { LocationIcon } from "@/shared/assets/icons"; +import { shadows } from "@/shared/styles/shadows"; + +interface MapSearchBarProps { + placeholder?: string; + onPress: () => void; +} + +export function MapSearchBar({ + placeholder = "찾으시는 제휴 가게가 없나요?", + onPress, +}: MapSearchBarProps) { + const insets = useSafeAreaInsets(); + + return ( + + + + + {placeholder} + + + + ); +} diff --git a/src/widgets/map/ui/MapView.tsx b/src/widgets/map/ui/MapView.tsx new file mode 100644 index 0000000..46f83e9 --- /dev/null +++ b/src/widgets/map/ui/MapView.tsx @@ -0,0 +1,5 @@ +import { View } from "react-native"; + +export function MapView() { + return ; +} diff --git a/src/widgets/map/ui/SearchResultCard.tsx b/src/widgets/map/ui/SearchResultCard.tsx new file mode 100644 index 0000000..bcf643a --- /dev/null +++ b/src/widgets/map/ui/SearchResultCard.tsx @@ -0,0 +1,25 @@ +import type { SearchResultStore } from "@/entities/store"; + +import { AdminStoreCard } from "./AdminStoreCard"; +import { StudentStoreCard } from "./StudentStoreCard"; + +type Role = "student" | "admin" | "partner"; + +interface SearchResultCardProps { + store: SearchResultStore; + role: Role; + onPress?: () => void; + onActionPress?: () => void; +} + +export function SearchResultCard({ + store, + role, + onPress, + onActionPress, +}: SearchResultCardProps) { + if (role === "student") { + return ; + } + return ; +} diff --git a/src/widgets/map/ui/StudentStoreCard.tsx b/src/widgets/map/ui/StudentStoreCard.tsx new file mode 100644 index 0000000..765962d --- /dev/null +++ b/src/widgets/map/ui/StudentStoreCard.tsx @@ -0,0 +1,60 @@ +import { Image, Pressable, Text, View } from "react-native"; + +import type { SearchResultStore } from "@/entities/store"; + +interface StudentStoreCardProps { + store: SearchResultStore; + onPress?: () => void; +} + +export function StudentStoreCard({ store, onPress }: StudentStoreCardProps) { + return ( + + + + + + {store.name} + + + {store.tag && ( + + + {store.tag} + + + )} + {store.benefit && ( + + {store.benefit} + + )} + + + + + ); +} + +function StoreImage({ uri }: { uri?: string }) { + return ( + + {uri ? ( + + ) : null} + + ); +} diff --git a/src/widgets/map/ui/index.ts b/src/widgets/map/ui/index.ts new file mode 100644 index 0000000..4c8b6ec --- /dev/null +++ b/src/widgets/map/ui/index.ts @@ -0,0 +1,5 @@ +export { AdminStoreCard } from "./AdminStoreCard"; +export { MapSearchBar } from "./MapSearchBar"; +export { MapView } from "./MapView"; +export { SearchResultCard } from "./SearchResultCard"; +export { StudentStoreCard } from "./StudentStoreCard"; diff --git a/yarn.lock b/yarn.lock index 05d0b4d..f687b09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2900,7 +2900,7 @@ base64-arraybuffer@^1.0.2: resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc" integrity sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ== -base64-js@^1.2.3, base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@^1.2.3, base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -8285,10 +8285,6 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@*, uuid@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-13.0.0.tgz#263dc341b19b4d755eb8fe36b78d95a6b65707e8" - integrity sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w== utrie@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/utrie/-/utrie-1.0.2.tgz#d42fe44de9bc0119c25de7f564a6ed1b2c87a645" @@ -8296,6 +8292,11 @@ utrie@^1.0.2: dependencies: base64-arraybuffer "^1.0.2" +uuid@*, uuid@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-13.0.0.tgz#263dc341b19b4d755eb8fe36b78d95a6b65707e8" + integrity sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w== + uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"