{ "openapi": "3.1.0", "info": { "title": "YAPP26 WEB2", "description": "SSOK 서비스 API 명세", "version": "v1" }, "servers": [ { "url": "https://api.ssok.info", "description": "Generated server url" } ], "tags": [ { "name": "USER API", "description": "사용자 관련 API" }, { "name": "숙소 API", "description": "숙소 관련 API" }, { "name": "OAUTH API", "description": "소셜 로그인 API" }, { "name": "비교표 API", "description": "비교표 관련 API" }, { "name": "여행 보드 API", "description": "여행 보드 관련 API" } ], "paths": { "/api/trip-boards/{tripBoardId}": { "get": { "tags": ["여행 보드 API"], "summary": "여행 보드 상세 조회", "description": "특정 여행 보드의 상세 정보를 조회합니다. JWT 인증을 통해 현재 사용자 정보를 추출하고, 여행 보드 참여자만 접근할 수 있습니다. 보드의 기본 정보, 참여자 목록, 사용자 역할 등을 포함한 완전한 정보를 반환합니다.", "operationId": "getTripBoardDetail", "parameters": [ { "name": "tripBoardId", "in": "path", "description": "조회할 여행 보드의 고유 ID", "required": true, "schema": { "type": "integer", "example": 1 } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTripBoardSummaryResponse" } } } } }, "security": [{ "JWT": [] }] }, "put": { "tags": ["여행 보드 API"], "summary": "여행 보드 수정", "description": "기존 여행 보드의 기본 정보(보드 이름, 목적지, 여행 기간)를 수정합니다. JWT 인증을 통해 현재 사용자 정보를 추출하고, 수정된 보드 정보를 반환합니다.", "operationId": "updateTripBoard", "parameters": [ { "name": "tripBoardId", "in": "path", "description": "여행 보드 ID", "required": true, "schema": { "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TripBoardUpdateRequest" } } }, "required": true }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTripBoardUpdateResponse" } } } } }, "security": [{ "JWT": [] }] }, "delete": { "tags": ["여행 보드 API"], "summary": "여행 보드 삭제", "description": "여행 보드와 관련된 모든 데이터를 삭제합니다. 오직 여행 보드의 소유자(OWNER)만이 삭제할 수 있으며, 삭제 시 해당 보드에 연관된 모든 리소스(숙소 정보, 멤버 매핑 관계, 비교표 등)가 함께 제거됩니다.", "operationId": "deleteTripBoard", "parameters": [ { "name": "tripBoardId", "in": "path", "description": "여행 보드 ID", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTripBoardDeleteResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/comparison/{tableId}": { "get": { "tags": ["비교표 API"], "summary": "비교표 조회", "description": "비교표 메타 데이터와 포함된 숙소 정보 리스트를 조회합니다. (Authorization 헤더에 Bearer 토큰 필요)", "operationId": "getComparisonTable", "parameters": [ { "name": "tableId", "in": "path", "description": "숙소가 포함된 테이블의 ID", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseComparisonTableResponse" } } } } }, "security": [{ "JWT": [] }] }, "put": { "tags": ["비교표 API"], "summary": "비교표 수정", "description": "비교표 메타 데이터(제목)와 숙소 세부 내용, 비교 기준 정렬 순서, 숙소 정렬 순서를 수정합니다. (Authorization 헤더에 Bearer 토큰 필요)", "operationId": "updateComparisonTable", "parameters": [ { "name": "tableId", "in": "path", "description": "수정할 테이블의 ID", "required": true, "schema": { "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateComparisonTableRequest" } } }, "required": true }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseBoolean" } } } } }, "security": [{ "JWT": [] }] }, "delete": { "tags": ["비교표 API"], "summary": "비교표 삭제", "description": "사용자가 생성한 비교표를 삭제합니다. 생성자만 삭제할 수 있습니다. (Authorization 헤더에 Bearer 토큰 필요)", "operationId": "deleteComparisonTable", "parameters": [ { "name": "tableId", "in": "path", "description": "삭제할 비교표의 ID", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "비교표 삭제 성공", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseComparisonTableDeleteResponse" } } } }, "401": { "description": "인증 실패 - 유효하지 않은 토큰 또는 인증 정보 없음", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseComparisonTableDeleteResponse" } } } }, "403": { "description": "권한 없음 - 비교표 생성자가 아님", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseComparisonTableDeleteResponse" } } } }, "404": { "description": "비교표를 찾을 수 없음", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseComparisonTableDeleteResponse" } } } }, "500": { "description": "서버 내부 오류 - 비교표 삭제 중 오류 발생", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseComparisonTableDeleteResponse" } } } } }, "security": [{ "JWT": [] }] }, "patch": { "tags": ["비교표 API"], "summary": "비교표 숙소 추가", "description": "비교표에 새로운 숙소를 추가합니다. (Authorization 헤더에 Bearer 토큰 필요)", "operationId": "addAccommodationToComparisonTable", "parameters": [ { "name": "tableId", "in": "path", "description": "테이블의 ID", "required": true, "schema": { "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddAccommodationRequest" } } }, "required": true }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseComparisonTableResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/trip-boards/register": { "post": { "tags": ["여행 보드 API"], "summary": "여행 보드 생성", "description": "새로운 여행 보드를 생성합니다. JWT 인증을 통해 현재 사용자 정보를 추출하고, 생성자는 자동으로 OWNER 역할로 등록되며 고유한 초대 코드가 생성됩니다.", "operationId": "createTripBoard", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TripBoardCreateRequest" } } }, "required": true }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTripBoardCreateResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/trip-boards/leave/{tripBoardId}": { "post": { "tags": ["여행 보드 API"], "summary": "여행 보드 나가기", "description": "여행 보드에서 나갑니다. OWNER인 경우 가장 먼저 입장한 MEMBER에게 권한이 이양되며, 마지막 참여자인 경우 여행보드가 삭제됩니다. 나가는 사용자는 자신이 생성한 리소스(비교표, 숙소)를 유지하거나 제거할 수 있습니다.", "operationId": "leaveTripBoard", "parameters": [ { "name": "tripBoardId", "in": "path", "description": "여행 보드 ID", "required": true, "schema": { "type": "integer" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TripBoardLeaveRequest" } } }, "required": true }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTripBoardLeaveResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/trip-boards/join": { "post": { "tags": ["여행 보드 API"], "summary": "여행 보드 참여", "description": "초대 코드를 통해 기존 여행 보드에 참여합니다. JWT 인증을 통해 현재 사용자 정보를 추출하고, 초대 코드의 유효성을 검증한 후 보드에 참여자로 등록합니다.", "operationId": "joinTripBoard", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TripBoardJoinRequest" } } }, "required": true }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTripBoardJoinResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/oauth/withdraw": { "post": { "tags": ["OAUTH API"], "summary": "사용자 회원탈퇴", "operationId": "withdrawUser", "responses": { "200": { "description": ".", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseWithdrawResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/oauth/refresh": { "post": { "tags": ["OAUTH API"], "summary": "리프레시 토큰 재발급", "description": "유효한 리프레시 토큰을 사용하여 새로운 액세스 토큰과 리프레시 토큰을 발급받습니다. 기존 리프레시 토큰은 무효화되고 새로운 토큰 쌍이 생성됩니다. 토큰 회전(Token Rotation)을 통해 보안을 강화합니다. 이 API는 액세스 토큰이 만료된 상황에서 사용되므로 JWT 인증이 필요하지 않습니다.", "operationId": "refreshTokens", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RefreshTokenRequest" } } }, "required": true }, "responses": { "200": { "description": "새로운 토큰이 성공적으로 발급되었습니다.", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTokenSuccessResponse" } } } }, "401": { "description": "리프레시 토큰이 유효하지 않거나 만료되었습니다.", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTokenSuccessResponse" } } } } } } }, "/api/oauth/logout": { "post": { "tags": ["OAUTH API"], "summary": "사용자 로그아웃", "description": "현재 로그인된 사용자의 세션을 종료합니다. 헤더에 있는 access-token 토큰을 블랙리스트에 추가하고, Redis에서 Refresh Token을 삭제합니다.로그아웃 후에는 새로운 인증이 필요합니다.", "operationId": "logout", "responses": { "200": { "description": "로그아웃이 성공적으로 완료되었습니다.", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseLogoutResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/oauth/kakao/token": { "post": { "tags": ["OAUTH API"], "summary": "카카오 OAuth 토큰 교환", "description": "카카오에서 발급받은 인가 코드를 통해 액세스 토큰을 획득하고, 사용자 정보를 조회하여 JWT 토큰을 헤더로 설정합니다. JWT 토큰은 응답 헤더로 전달되며, 응답 바디에는 사용자 정보만 포함됩니다. 인가 코드와 baseUrl은 Query Parameter로 전달해야 합니다. 로그인 성공 후 응답 헤더 access-token, 쿠키 REFRESH_TOKEN 로 각각 액세스 토큰, 리프레시 토큰이 전달됩니다.", "operationId": "exchangeKakaoToken", "parameters": [ { "name": "code", "in": "query", "required": true, "schema": { "type": "string" } }, { "name": "baseUrl", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "JWT 토큰이 쿠키로 성공적으로 설정되고, 사용자 정보가 반환됩니다.", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseOauthLoginResponse" } } } } } } }, "/api/comparison/new": { "post": { "tags": ["비교표 API"], "summary": "비교표 생성", "description": "비교표 이름, 숙소 ID 리스트, 비교 기준 항목을 받아서 비교표 메타 데이터를 생성합니다. (Authorization 헤더에 Bearer 토큰 필요)", "operationId": "createComparisonTable", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateComparisonTableRequest" } } }, "required": true }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseCreateComparisonTableResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/accommodations/register": { "post": { "tags": ["숙소 API"], "summary": "숙소 카드 등록", "description": "링크를 첨부하여 숙소 카드를 등록합니다.", "operationId": "registerAccommodationCard", "requestBody": { "description": "숙소 등록 요청 데이터", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AccommodationRegisterRequest" } } }, "required": true }, "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseAccommodationRegisterResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/trip-boards/{tripBoardId}/invitation/toggle": { "patch": { "tags": ["여행 보드 API"], "summary": "초대 링크 활성화/비활성화 토글", "description": "여행 보드의 초대 링크 활성화 상태를 토글합니다. 현재 상태의 반대로 변경되며, 활성화된 초대 링크만 사용하여 여행 보드에 참여할 수 있습니다.", "operationId": "toggleInvitationActive", "parameters": [ { "name": "tripBoardId", "in": "path", "description": "여행 보드 ID", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseInvitationToggleResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/users/me": { "get": { "tags": ["USER API"], "summary": "사용자 정보 조회", "description": "현재 로그인한 사용자의 기본 정보(닉네임, 프로필 이미지)를 조회합니다.", "operationId": "getUserInfo", "responses": { "200": { "description": "사용자 정보 조회 성공", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseUserInfoResponse" } } } }, "401": { "description": "인증되지 않은 사용자", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseUserInfoResponse" } } } }, "404": { "description": "사용자를 찾을 수 없음 또는 탈퇴한 사용자", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseUserInfoResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/trip-boards/{tripBoardId}/invitation": { "get": { "tags": ["여행 보드 API"], "summary": "초대 링크 정보 조회", "description": "여행 보드에서 현재 사용자의 초대 링크 정보를 조회합니다. 초대 코드, 활성화 상태 등의 정보를 포함합니다.", "operationId": "getInvitationCode", "parameters": [ { "name": "tripBoardId", "in": "path", "description": "여행 보드 ID", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseInvitationCodeResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/trip-boards/search": { "get": { "tags": ["여행 보드 API"], "summary": "여행 보드 목록 조회", "description": "사용자가 참여한 여행 보드 목록을 페이징으로 조회합니다. JWT 인증을 통해 현재 사용자 정보를 추출하고, 최신순으로 정렬된 결과를 반환합니다.", "operationId": "getTripBoards", "parameters": [ { "name": "page", "in": "query", "description": "페이지 번호", "required": true, "schema": { "type": "integer", "minimum": 0 } }, { "name": "size", "in": "query", "description": "페이지 크기", "required": true, "schema": { "type": "integer", "minimum": 1 } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseTripBoardPageResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/oauth/kakao/authorize": { "get": { "tags": ["OAUTH API"], "summary": "카카오 OAuth 인가 URL 조회", "description": "카카오 OAuth 인가 페이지 URL을 반환합니다. 클라이언트의 baseUrl을 기반으로 동적으로 redirect_uri를 생성합니다. 프론트엔드에서 이 URL로 리다이렉트하여 사용자 인증을 진행합니다.", "operationId": "getKakaoAuthorizeUrl", "parameters": [ { "name": "baseUrl", "in": "query", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "description": "카카오 OAuth 인가 URL이 성공적으로 반환됩니다.", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseAuthorizeUrlResponse" } } } } } } }, "/api/comparison/factors": { "get": { "tags": ["비교표 API"], "summary": "비교표 기준 항목 Enum 리스트", "description": "비교 기준 항목 Enum 리스트를 반환합니다.", "operationId": "getComparisonFactorList", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseComparisonFactorList" } } } } } } }, "/api/comparison/amenity": { "get": { "tags": ["비교표 API"], "summary": "편의 서비스 Enum 리스트", "description": "편의 서비스 항목 Enum 리스트를 반환합니다.", "operationId": "getAmenityFactorList", "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseAmenityFactorList" } } } } } } }, "/api/accommodations/{accommodationId}": { "get": { "tags": ["숙소 API"], "summary": "숙소 단건 조회", "description": "특정 숙소 ID로 숙소 정보를 조회합니다.", "operationId": "getAccommodationById", "parameters": [ { "name": "accommodationId", "in": "path", "description": "조회할 숙소의 ID", "required": true, "schema": { "type": "integer", "format": "int64", "minimum": 1 } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseAccommodationResponse" } } } } }, "security": [{ "JWT": [] }] }, "delete": { "tags": ["숙소 API"], "summary": "숙소 삭제", "description": "본인이 등록한 숙소를 삭제합니다.", "operationId": "deleteAccommodation", "parameters": [ { "name": "accommodationId", "in": "path", "description": "삭제할 숙소의 ID", "required": true, "schema": { "type": "integer", "format": "int64", "minimum": 1 } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseAccommodationDeleteResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/accommodations/search": { "get": { "tags": ["숙소 API"], "summary": "숙소 목록 조회", "description": "숙소 목록을 조회합니다.", "operationId": "getAccommodationByTripBoardIdAndUserId", "parameters": [ { "name": "tripBoardId", "in": "query", "description": "숙소가 포함된 여행보드의 ID", "required": true, "schema": { "type": "integer", "minimum": 1 } }, { "name": "page", "in": "query", "description": "페이지 번호", "required": true, "schema": { "type": "integer", "minimum": 0 } }, { "name": "size", "in": "query", "description": "페이지 크기", "required": true, "schema": { "type": "integer", "minimum": 1 } }, { "name": "userId", "in": "query", "description": "유저 ID, 없는 경우 모든 유저가 생성한 숙소 목록을 반환합니다. 현재 parameter로 받는 것은 임시 로직입니다.", "required": false, "schema": { "type": "integer", "format": "int64" } }, { "name": "sort", "in": "query", "description": "정렬 기준, 기본 값은 saved_at_desc(최근 등록순)이고, price_asc(최저 가격순)을 제공합니다.", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseAccommodationPageResponse" } } } } }, "security": [{ "JWT": [] }] } }, "/api/accommodations/count": { "get": { "tags": ["숙소 API"], "summary": "여행보드 숙소 개수 조회", "description": "여행보드에 포함된 숙소의 개수를 조회합니다.", "operationId": "getAccommodationCountByTripBoardId", "parameters": [ { "name": "tripBoardId", "in": "query", "description": "숙소가 포함된 여행보드의 ID", "required": true, "schema": { "type": "integer", "format": "int64", "minimum": 1 } }, { "name": "userId", "in": "query", "description": "유저 ID, 없는 경우 모든 유저가 생성한 숙소 목록을 반환합니다. 현재 parameter로 받는 것은 임시 로직입니다.", "required": false, "schema": { "type": "integer", "format": "int64" } } ], "responses": { "200": { "description": "OK", "content": { "*/*": { "schema": { "$ref": "#/components/schemas/StandardResponseAccommodationCountResponse" } } } } }, "security": [{ "JWT": [] }] } } }, "components": { "schemas": { "TripBoardUpdateRequest": { "type": "object", "properties": { "boardName": { "type": "string", "maxLength": 20, "minLength": 0 }, "destination": { "type": "string", "maxLength": 20, "minLength": 0, "pattern": "^[가-힣a-zA-Z\\s]+$" }, "startDate": { "type": "string", "format": "date" }, "endDate": { "type": "string", "format": "date" } }, "required": ["endDate", "startDate"] }, "StandardResponseTripBoardUpdateResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/TripBoardUpdateResponse", "description": "응답 결과 데이터" } } }, "TripBoardUpdateResponse": { "type": "object", "properties": { "tripBoardId": { "type": "integer", "format": "int64" }, "boardName": { "type": "string" }, "destination": { "type": "string" }, "startDate": { "type": "string", "format": "date" }, "endDate": { "type": "string", "format": "date" }, "updatedAt": { "type": "string", "format": "date-time" } } }, "AmenityUpdate": { "type": "object", "properties": { "type": { "type": "string" }, "available": { "type": "boolean" }, "description": { "type": "string" } }, "required": ["type"] }, "AttractionUpdate": { "type": "object", "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "distance": { "type": "string" }, "latitude": { "type": "number", "format": "double" }, "longitude": { "type": "number", "format": "double" }, "byFoot": { "$ref": "#/components/schemas/DistanceInfo" }, "byCar": { "$ref": "#/components/schemas/DistanceInfo" } } }, "CheckTimeUpdate": { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } } }, "DistanceInfo": { "type": "object", "properties": { "distance": { "type": "string" }, "time": { "type": "string" } } }, "TransportationUpdate": { "type": "object", "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "distance": { "type": "string" }, "latitude": { "type": "number", "format": "double" }, "longitude": { "type": "number", "format": "double" }, "byFoot": { "$ref": "#/components/schemas/DistanceInfo" }, "byCar": { "$ref": "#/components/schemas/DistanceInfo" } } }, "UpdateAccommodationRequest": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64" }, "memo": { "type": "string", "maxLength": 100, "minLength": 0 }, "lowestPrice": { "type": "integer", "format": "int32" }, "currency": { "type": "string" }, "reviewScore": { "type": "number", "format": "double" }, "cleanlinessScore": { "type": "number", "format": "double" }, "reviewSummary": { "type": "string", "maxLength": 100, "minLength": 0 }, "nearbyAttractions": { "type": "array", "items": { "$ref": "#/components/schemas/AttractionUpdate" } }, "nearbyTransportation": { "type": "array", "items": { "$ref": "#/components/schemas/TransportationUpdate" } }, "amenities": { "type": "array", "items": { "$ref": "#/components/schemas/AmenityUpdate" } }, "checkInTime": { "$ref": "#/components/schemas/CheckTimeUpdate" }, "checkOutTime": { "$ref": "#/components/schemas/CheckTimeUpdate" } } }, "UpdateComparisonTableRequest": { "type": "object", "properties": { "tripBoardId": { "type": "integer", "format": "int64" }, "tableName": { "type": "string", "minLength": 1 }, "accommodationRequestList": { "type": "array", "items": { "$ref": "#/components/schemas/UpdateAccommodationRequest" } }, "accommodationIdList": { "type": "array", "items": { "type": "integer", "format": "int64" }, "minItems": 1 }, "factorList": { "type": "array", "items": { "type": "string" }, "minItems": 1 } }, "required": ["accommodationRequestList", "tripBoardId"] }, "StandardResponseBoolean": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "type": "boolean", "description": "응답 결과 데이터" } } }, "TripBoardCreateRequest": { "type": "object", "properties": { "boardName": { "type": "string", "maxLength": 20, "minLength": 0 }, "destination": { "type": "string", "maxLength": 20, "minLength": 0, "pattern": "^[가-힣a-zA-Z\\s]+$" }, "startDate": { "type": "string", "format": "date" }, "endDate": { "type": "string", "format": "date" } }, "required": ["endDate", "startDate"] }, "StandardResponseTripBoardCreateResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/TripBoardCreateResponse", "description": "응답 결과 데이터" } } }, "TripBoardCreateResponse": { "type": "object", "properties": { "tripBoardId": { "type": "integer", "format": "int64" }, "boardName": { "type": "string" }, "destination": { "type": "string" }, "travelPeriod": { "type": "string" }, "startDate": { "type": "string" }, "endDate": { "type": "string" }, "invitationCode": { "type": "string" }, "invitationActive": { "type": "boolean" }, "creator": { "$ref": "#/components/schemas/UserInfo" }, "createdAt": { "type": "string", "format": "date-time" } } }, "UserInfo": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64" }, "nickname": { "type": "string" }, "email": { "type": "string" }, "profileImage": { "type": "string" } } }, "TripBoardLeaveRequest": { "type": "object", "properties": { "removeResources": { "type": "boolean" } }, "required": ["removeResources"] }, "StandardResponseTripBoardLeaveResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/TripBoardLeaveResponse", "description": "응답 결과 데이터" } } }, "TripBoardLeaveResponse": { "type": "object", "properties": { "tripBoardId": { "type": "integer", "format": "int64" }, "leftAt": { "type": "string", "format": "date-time" } } }, "TripBoardJoinRequest": { "type": "object", "description": "여행 보드 참여 요청", "properties": { "invitationCode": { "type": "string", "description": "여행 보드 초대 코드", "example": "abc123def456", "minLength": 1, "pattern": "^[0-9a-fA-F]{32}$" } }, "required": ["invitationCode"] }, "StandardResponseTripBoardJoinResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/TripBoardJoinResponse", "description": "응답 결과 데이터" } } }, "TripBoardJoinResponse": { "type": "object", "description": "여행 보드 참여 응답", "properties": { "tripBoardId": { "type": "integer", "format": "int64", "description": "여행 보드 ID", "example": 1 }, "boardName": { "type": "string", "description": "여행 보드 이름", "example": "제주도 여행" }, "destination": { "type": "string", "description": "여행 목적지", "example": "제주도" }, "travelPeriod": { "type": "string", "description": "여행 기간", "example": "25.08.14~08.16" }, "participantCount": { "type": "integer", "format": "int32", "description": "현재 참여자 수", "example": 3 }, "joinedAt": { "type": "string", "format": "date-time", "description": "보드 참여 시간", "example": "2025-01-09T10:30:00" } } }, "StandardResponseWithdrawResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/WithdrawResponse", "description": "응답 결과 데이터" } } }, "WithdrawResponse": { "type": "object", "properties": { "withdrawSuccess": { "type": "boolean" } } }, "RefreshTokenRequest": { "type": "object", "description": "리프레시 토큰 재발급 요청", "properties": { "refreshToken": { "type": "string", "description": "리프레시 토큰", "minLength": 1 } } }, "StandardResponseTokenSuccessResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/TokenSuccessResponse", "description": "응답 결과 데이터" } } }, "TokenSuccessResponse": { "type": "object", "description": "토큰 발급 응답", "properties": { "accessToken": { "type": "string", "description": "액세스 토큰", "example": "access-token-example", "readOnly": true }, "refreshToken": { "type": "string", "description": "리프레시 토큰", "example": "refresh-token-example", "readOnly": true } } }, "LogoutResponse": { "type": "object", "properties": { "logoutSuccess": { "type": "boolean" } } }, "StandardResponseLogoutResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/LogoutResponse", "description": "응답 결과 데이터" } } }, "OauthLoginResponse": { "type": "object", "description": "OAuth 로그인 응답", "properties": { "userId": { "type": "integer", "format": "int64", "description": "사용자 ID", "example": 12345 }, "nickname": { "type": "string", "description": "사용자 닉네임", "example": "홍길동" }, "token": { "$ref": "#/components/schemas/TokenSuccessResponse", "description": "토큰 정보" } } }, "StandardResponseOauthLoginResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/OauthLoginResponse", "description": "응답 결과 데이터" } } }, "CreateComparisonTableRequest": { "type": "object", "properties": { "tripBoardId": { "type": "integer", "format": "int64" }, "tableName": { "type": "string", "minLength": 1 }, "accommodationIdList": { "type": "array", "items": { "type": "integer", "format": "int64" }, "minItems": 1 }, "factorList": { "type": "array", "items": { "type": "string" } } }, "required": ["tripBoardId"] }, "CreateComparisonTableResponse": { "type": "object", "properties": { "tableId": { "type": "integer", "format": "int64" } } }, "StandardResponseCreateComparisonTableResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/CreateComparisonTableResponse", "description": "응답 결과 데이터" } } }, "AccommodationRegisterRequest": { "type": "object", "properties": { "url": { "type": "string", "minLength": 1 }, "memo": { "type": "string", "maxLength": 50, "minLength": 0 }, "tripBoardId": { "type": "integer", "format": "int64" } }, "required": ["tripBoardId"] }, "AccommodationRegisterResponse": { "type": "object", "properties": { "accommodationId": { "type": "integer", "format": "int64" } } }, "StandardResponseAccommodationRegisterResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/AccommodationRegisterResponse", "description": "응답 결과 데이터" } } }, "InvitationToggleResponse": { "type": "object", "description": "초대 링크 활성화/비활성화 토글 응답", "properties": { "tripBoardId": { "type": "integer", "format": "int64", "description": "여행 보드 ID", "example": 1 }, "isActive": { "type": "boolean", "description": "초대 링크 활성화 여부", "example": true }, "invitationCode": { "type": "string", "description": "초대 코드", "example": "ABC123DEF" } } }, "StandardResponseInvitationToggleResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/InvitationToggleResponse", "description": "응답 결과 데이터" } } }, "AddAccommodationRequest": { "type": "object", "properties": { "accommodationIds": { "type": "array", "items": { "type": "integer", "format": "int64" } } }, "required": ["accommodationIds"] }, "AccommodationResponse": { "type": "object", "properties": { "id": { "type": "integer", "format": "int64" }, "url": { "type": "string" }, "siteName": { "type": "string" }, "logoUrl": { "type": "string" }, "memo": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "createdBy": { "type": "integer", "format": "int64" }, "tripBoardId": { "type": "integer", "format": "int64" }, "accommodationName": { "type": "string" }, "images": { "type": "array", "items": { "type": "string" } }, "address": { "type": "string" }, "latitude": { "type": "number", "format": "double" }, "longitude": { "type": "number", "format": "double" }, "lowestPrice": { "type": "integer", "format": "int32" }, "highestPrice": { "type": "integer", "format": "int32" }, "currency": { "type": "string" }, "reviewScore": { "type": "number", "format": "double" }, "cleanlinessScore": { "type": "number", "format": "double" }, "reviewSummary": { "type": "string" }, "hotelId": { "type": "integer", "format": "int64" }, "nearbyAttractions": { "type": "array", "items": { "$ref": "#/components/schemas/Attraction" } }, "nearbyTransportation": { "type": "array", "items": { "$ref": "#/components/schemas/Transportation" } }, "amenities": { "type": "array", "items": { "$ref": "#/components/schemas/Amenity" } }, "checkInTime": { "$ref": "#/components/schemas/CheckTime" }, "checkOutTime": { "$ref": "#/components/schemas/CheckTime" } } }, "Amenity": { "type": "object", "properties": { "type": { "type": "string" }, "available": { "type": "boolean" }, "description": { "type": "string" } } }, "Attraction": { "type": "object", "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "latitude": { "type": "number", "format": "double" }, "longitude": { "type": "number", "format": "double" }, "distance": { "type": "string" }, "byFoot": { "$ref": "#/components/schemas/DistanceInfo" }, "byCar": { "$ref": "#/components/schemas/DistanceInfo" } } }, "CheckTime": { "type": "object", "properties": { "from": { "type": "string" }, "to": { "type": "string" } } }, "ComparisonTableResponse": { "type": "object", "properties": { "tableId": { "type": "integer", "format": "int64" }, "tableName": { "type": "string" }, "accommodationResponsesList": { "type": "array", "items": { "$ref": "#/components/schemas/AccommodationResponse" } }, "factorsList": { "type": "array", "items": { "type": "string", "enum": [ "REVIEW_SCORE", "ATTRACTION", "TRANSPORTATION", "CLEANLINESS", "AMENITY", "CHECK_TIME", "REVIEW_SUMMARY", "MEMO" ] } }, "createdBy": { "type": "integer", "format": "int64" } } }, "StandardResponseComparisonTableResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/ComparisonTableResponse", "description": "응답 결과 데이터" } } }, "Transportation": { "type": "object", "properties": { "name": { "type": "string" }, "type": { "type": "string" }, "latitude": { "type": "number", "format": "double" }, "longitude": { "type": "number", "format": "double" }, "distance": { "type": "string" }, "byFoot": { "$ref": "#/components/schemas/DistanceInfo" }, "byCar": { "$ref": "#/components/schemas/DistanceInfo" } } }, "StandardResponseUserInfoResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/UserInfoResponse", "description": "응답 결과 데이터" } } }, "UserInfoResponse": { "type": "object", "description": "유저 정보 응답", "properties": { "nickname": { "type": "string", "description": "유저 닉네임", "example": "홍길동" }, "profileImageUrl": { "type": "string", "description": "유저 프로필 이미지 URL", "example": "https://example.com/profile/user123.jpg" } } }, "ParticipantProfileResponse": { "type": "object", "properties": { "userId": { "type": "integer", "format": "int64" }, "profileImageUrl": { "type": "string" }, "nickname": { "type": "string" }, "role": { "type": "string", "enum": ["OWNER", "MEMBER"] } } }, "StandardResponseTripBoardSummaryResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/TripBoardSummaryResponse", "description": "응답 결과 데이터" } } }, "TripBoardSummaryResponse": { "type": "object", "properties": { "tripBoardId": { "type": "integer", "format": "int64" }, "boardName": { "type": "string" }, "destination": { "type": "string" }, "startDate": { "type": "string", "format": "date" }, "endDate": { "type": "string", "format": "date" }, "travelPeriod": { "type": "string" }, "userRole": { "type": "string", "enum": ["OWNER", "MEMBER"] }, "participantCount": { "type": "integer", "format": "int32" }, "accommodationCount": { "type": "integer", "format": "int32" }, "participants": { "type": "array", "items": { "$ref": "#/components/schemas/ParticipantProfileResponse" } }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" } } }, "InvitationCodeResponse": { "type": "object", "description": "사용자의 초대 링크 정보 조회 응답", "properties": { "tripBoardId": { "type": "integer", "format": "int64", "description": "여행 보드 ID", "example": 1 }, "isActive": { "type": "boolean", "description": "초대 링크 활성화 여부", "example": true }, "invitationCode": { "type": "string", "description": "초대 코드", "example": "ABC123DEF" } } }, "StandardResponseInvitationCodeResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/InvitationCodeResponse", "description": "응답 결과 데이터" } } }, "StandardResponseTripBoardPageResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/TripBoardPageResponse", "description": "응답 결과 데이터" } } }, "TripBoardPageResponse": { "type": "object", "properties": { "tripBoards": { "type": "array", "items": { "$ref": "#/components/schemas/TripBoardSummaryResponse" } }, "hasNext": { "type": "boolean" } } }, "AuthorizeUrlResponse": { "type": "object", "description": "OAuth 인가 URL 응답", "properties": { "authorizeUrl": { "type": "string", "description": "카카오 OAuth 인가 URL", "example": "https://kauth.kakao.com/oauth/authorize?client_id=..." } } }, "StandardResponseAuthorizeUrlResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/AuthorizeUrlResponse", "description": "응답 결과 데이터" } } }, "ComparisonFactorList": { "type": "object", "properties": { "factors": { "type": "array", "items": { "type": "string", "enum": [ "REVIEW_SCORE", "ATTRACTION", "TRANSPORTATION", "CLEANLINESS", "AMENITY", "CHECK_TIME", "REVIEW_SUMMARY", "MEMO" ] } } } }, "StandardResponseComparisonFactorList": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/ComparisonFactorList", "description": "응답 결과 데이터" } } }, "AmenityFactorList": { "type": "object", "properties": { "factors": { "type": "array", "items": { "type": "string", "enum": [ "PARKING", "BREAKFAST", "FREE_WIFI", "POOL", "FITNESS", "LUGGAGE_STORAGE", "BAR_LOUNGE", "FRONT_DESK_HOURS", "PET_FRIENDLY", "BUSINESS_SERVICES", "CLEANING_SERVICE", "HANDICAP_FACILITIES" ] } } } }, "StandardResponseAmenityFactorList": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/AmenityFactorList", "description": "응답 결과 데이터" } } }, "StandardResponseAccommodationResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/AccommodationResponse", "description": "응답 결과 데이터" } } }, "AccommodationPageResponse": { "type": "object", "properties": { "accommodations": { "type": "array", "items": { "$ref": "#/components/schemas/AccommodationResponse" } }, "hasNext": { "type": "boolean" } } }, "StandardResponseAccommodationPageResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/AccommodationPageResponse", "description": "응답 결과 데이터" } } }, "AccommodationCountResponse": { "type": "object", "properties": { "accommodationCount": { "type": "integer", "format": "int64" } } }, "StandardResponseAccommodationCountResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/AccommodationCountResponse", "description": "응답 결과 데이터" } } }, "StandardResponseTripBoardDeleteResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/TripBoardDeleteResponse", "description": "응답 결과 데이터" } } }, "TripBoardDeleteResponse": { "type": "object", "properties": { "tripBoardId": { "type": "integer", "format": "int64" } } }, "ComparisonTableDeleteResponse": { "type": "object", "properties": { "tableId": { "type": "integer", "format": "int64" }, "message": { "type": "string" } } }, "StandardResponseComparisonTableDeleteResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/ComparisonTableDeleteResponse", "description": "응답 결과 데이터" } } }, "AccommodationDeleteResponse": { "type": "object", "properties": { "accommodationId": { "type": "integer", "format": "int64" } } }, "StandardResponseAccommodationDeleteResponse": { "type": "object", "description": "API 응답의 표준 형식을 정의하는 클래스", "properties": { "responseType": { "type": "string", "description": "응답 유형", "enum": ["SUCCESS", "ERROR"], "example": "SUCCESS" }, "result": { "$ref": "#/components/schemas/AccommodationDeleteResponse", "description": "응답 결과 데이터" } } } }, "securitySchemes": { "JWT": { "type": "http", "description": "JWT Access Token을 Authorization 헤더로 전송", "scheme": "bearer", "bearerFormat": "JWT" } } } }