diff --git a/src/main/java/com/example/Centralthon/domain/menu/web/controller/MenuApi.java b/src/main/java/com/example/Centralthon/domain/menu/web/controller/MenuApi.java
new file mode 100644
index 0000000..95c51b4
--- /dev/null
+++ b/src/main/java/com/example/Centralthon/domain/menu/web/controller/MenuApi.java
@@ -0,0 +1,158 @@
+package com.example.Centralthon.domain.menu.web.controller;
+
+import com.example.Centralthon.domain.menu.web.dto.MenuDetailsRes;
+import com.example.Centralthon.domain.menu.web.dto.MenuIdsReq;
+import com.example.Centralthon.domain.menu.web.dto.NearbyMenusRes;
+import com.example.Centralthon.domain.menu.web.dto.StoresByMenuRes;
+import com.example.Centralthon.global.response.SuccessResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.validation.Valid;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+
+@Tag(name = "Menus", description = "반찬 관련 API")
+public interface MenuApi {
+ @Operation(
+ summary = "맞춤 추천용 메뉴 목록 조회",
+ description ="사용자 위치 기준 2km 이내에 가게에서 판매중인 반찬 매물을 반환합니다.
"+
+ "중복을 제외하고 { 반찬명, 카테고리 }를 반환합니다.")
+ @ApiResponse(
+ responseCode = "200",
+ description = "맞춤 추천용 메뉴 목록 조회 성공",
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = SuccessResponse.class),
+ examples = @ExampleObject(
+ name = "SUCCESS_200",
+ value = """
+ {
+ "timestamp": "2025-08-15 04:22:54",
+ "code": "SUCCESS_200",
+ "httpStatus": 200,
+ "message": "호출에 성공하였습니다.",
+ "data": [
+ {
+ "name": "진미채 볶음",
+ "category" : "STIR_FRY"
+ },
+ {
+ "name": "두부 조림",
+ "category" : "BRAISED"
+ }
+ ],
+ "isSuccess": true
+ }
+ """
+ )
+ )
+ )
+ ResponseEntity>> nearbyMenus(
+ @Parameter(name = "lat", description = "사용자 위도", example = "37.468355", required = true)
+ @RequestParam("lat") Double lat,
+ @Parameter(name = "lng", description = "사용자 경도", example = "127.039073", required = true)
+ @RequestParam("lng") Double lng);
+
+ @Operation(
+ summary = "특정 메뉴 판매 가게 조회",
+ description = "반찬명을 기준으로 해당 메뉴를 판매하는 가게를 조회합니다. 공백까지 포함하여 동일 여부를 판단합니다.
"+
+ "{ 메뉴Id값, 가게명, 사용자-가게 거리(km), 할인가, 수량}을 반환합니다.")
+ @ApiResponse(
+ responseCode = "200",
+ description = "특정 메뉴 판매 가게 조회 성공",
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = SuccessResponse.class),
+ examples = @ExampleObject(
+ name = "SUCCESS_200",
+ value = """
+ {
+ "timestamp": "2025-08-15 04:22:54",
+ "code": "SUCCESS_200",
+ "httpStatus": 200,
+ "message": "호출에 성공하였습니다.",
+ "data": [
+ {
+ "menuId": 15,
+ "storeName": "초록찬 비건키친",
+ "distance": 1.7047542239779305,
+ "salePrice": 4000,
+ "quantity": 7
+ },
+ {
+ "menuId": 1,
+ "storeName": "우찬이네 반찬",
+ "distance": 1.0348092111962985,
+ "salePrice": 4200,
+ "quantity": 10
+ }
+ ],
+ "isSuccess": true
+ }
+ """
+ )
+ )
+ )
+ ResponseEntity>> storesByMenu(
+ @Parameter(name = "name", description = "메뉴 이름(공백 포함하여 완전일치)", example = "두부 조림", required = true)
+ @RequestParam("name") String name,
+ @Parameter(name = "lat", description = "사용자 위도", example = "37.468355", required = true)
+ @RequestParam("lat") Double lat,
+ @Parameter(name = "lng", description = "사용자 경도", example = "127.039073", required = true)
+ @RequestParam("lng") Double lng);
+
+ @Operation(
+ summary = "메뉴 상세 조회",
+ description = "사용자가 추가한 각 메뉴들의 상세 정보를 반환합니다.
"+
+ "{메뉴Id값, 메뉴 이름, 카테고리, 원가, 할인가, 할인율, 가게명}을 반환합니다."
+ )
+ @ApiResponse(
+ responseCode = "200",
+ description = "메뉴 상세 조회 성공",
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = SuccessResponse.class),
+ examples = @ExampleObject(
+ name = "SUCCESS_200",
+ value = """
+ {
+ "timestamp": "2025-08-15 04:22:54",
+ "code": "SUCCESS_200",
+ "httpStatus": 200,
+ "message": "호출에 성공하였습니다.",
+ "data": [
+ {
+ "menuId": 1,
+ "name": "진미채 볶음",
+ "category" : "STIR_FRY",
+ "costPrice" : 3000,
+ "salePrice" : 2400,
+ "salePercent" : 20,
+ "storeName" : "우찬이네 밥상"
+ },
+ {
+ "menuId": 4,
+ "name": "두부 조림",
+ "category" : "BRAISED",
+ "costPrice" : 5000,
+ "salePrice" : 4000,
+ "salePercent" : 20,
+ "storeName" : "희망 식당"
+ }
+ ],
+ "isSuccess": true
+ }
+ """
+ )
+ )
+ )
+ ResponseEntity>> details(@RequestBody @Valid MenuIdsReq menus);
+}
diff --git a/src/main/java/com/example/Centralthon/domain/menu/web/controller/MenuController.java b/src/main/java/com/example/Centralthon/domain/menu/web/controller/MenuController.java
index b442449..3598235 100644
--- a/src/main/java/com/example/Centralthon/domain/menu/web/controller/MenuController.java
+++ b/src/main/java/com/example/Centralthon/domain/menu/web/controller/MenuController.java
@@ -3,6 +3,7 @@
import com.example.Centralthon.domain.menu.service.MenuService;
import com.example.Centralthon.domain.menu.web.dto.*;
+import com.example.Centralthon.domain.order.web.controller.OrderApi;
import com.example.Centralthon.global.response.SuccessResponse;
import jakarta.validation.Valid;
@@ -21,11 +22,12 @@
@RestController
@RequestMapping("/api/menus")
@RequiredArgsConstructor
-public class MenuController {
+public class MenuController implements MenuApi {
private final MenuService menuService;
//맞춤 추천용 메뉴 목록 조회
@GetMapping("")
+ @Override
public ResponseEntity>> nearbyMenus(
@RequestParam("lat") Double lat,
@RequestParam("lng") Double lng) {
@@ -37,6 +39,7 @@ public ResponseEntity>> nearbyMenus(
//특정 메뉴를 판매 하는 가게 조회
@GetMapping("/stores")
+ @Override
public ResponseEntity>> storesByMenu(
@RequestParam("name") String name,
@RequestParam("lat") Double lat,
@@ -49,6 +52,7 @@ public ResponseEntity>> storesByMenu(
//메뉴 상세 조회
@PostMapping("/details")
+ @Override
public ResponseEntity>> details(@RequestBody @Valid MenuIdsReq menus){
List menuList = menuService.details(menus);
diff --git a/src/main/java/com/example/Centralthon/domain/store/web/controller/StoreApi.java b/src/main/java/com/example/Centralthon/domain/store/web/controller/StoreApi.java
new file mode 100644
index 0000000..92f0098
--- /dev/null
+++ b/src/main/java/com/example/Centralthon/domain/store/web/controller/StoreApi.java
@@ -0,0 +1,123 @@
+package com.example.Centralthon.domain.store.web.controller;
+
+import com.example.Centralthon.domain.order.web.dto.CompleteOrderReq;
+import com.example.Centralthon.domain.order.web.dto.CreateOrderReq;
+import com.example.Centralthon.domain.order.web.dto.CreateOrderRes;
+import com.example.Centralthon.domain.store.web.dto.NearbyStoresRes;
+import com.example.Centralthon.domain.store.web.dto.StoreMenusRes;
+import com.example.Centralthon.global.response.SuccessResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+
+@Tag(name = "Stores", description = "가게 관련 API")
+public interface StoreApi {
+ @Operation(
+ summary = "근처 가게 위치 목록 조회",
+ description = "사용자 위치 기준 2km 반경 내에 가게 목록을 조회합니다.
가게들의 기본키와 좌표값(위도, 경도)을 반환합니다."
+ )
+ @ApiResponse(
+ responseCode = "200",
+ description = "근처 가게 조회 성공",
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = SuccessResponse.class),
+ examples = @ExampleObject(
+ name = "SUCCESS_200",
+ value = """
+ {
+ "timestamp": "2025-08-14 15:54:04",
+ "code": "SUCCESS_200",
+ "httpStatus": 200,
+ "message": "호출에 성공하였습니다.",
+ "data": [
+ {
+ "storeId": 1,
+ "lat": 37.59,
+ "lng": 127.0164
+ },
+ {
+ "storeId": 2,
+ "lat": 37.577,
+ "lng": 127.0204
+ }
+ ],
+ "isSuccess": true
+ }
+ """
+ )
+ )
+ )
+ ResponseEntity>> nearbyStores(
+ @Parameter(name = "lat", description = "사용자 위도", example = "37.468355", required = true)
+ @RequestParam("lat") Double lat,
+ @Parameter(name = "lng", description = "사용자 경도", example = "127.039073", required = true)
+ @RequestParam("lng") Double lng);
+
+ @Operation(
+ summary = "가게에서 판매 중인 메뉴 조회",
+ description ="현재 재고가 있고 마감 기한을 넘지 않은 메뉴들의 목록을 반환합니다. distacne = 사용자와 가게간의 거리(km)
" +
+ "{ 메뉴 Id값, 이름, 카테고리, 원가, 할인가, 할인율, 수량} 을 반환합니다.")
+ @ApiResponse(
+ responseCode = "200",
+ description = "판매 메뉴 목록 조회 성공",
+ content = @Content(
+ mediaType = "application/json",
+ schema = @Schema(implementation = SuccessResponse.class),
+ examples = @ExampleObject(
+ name = "SUCCESS_200",
+ value = """
+ {
+ "timestamp": "2025-08-15 04:45:14",
+ "code": "SUCCESS_200",
+ "httpStatus": 200,
+ "message": "호출에 성공하였습니다.",
+ "data": {
+ "name": "오색퓨전찬",
+ "category": "FUSION_SIDE_DISH",
+ "distance": 1.0419556581490452,
+ "menus": [
+ {
+ "menuId": 4,
+ "name": "진미채 볶음",
+ "category": "STIR_FRY",
+ "costPrice": 5000,
+ "salePrice": 4500,
+ "salePercent": 10,
+ "quantity": 7
+ },
+ {
+ "menuId": 6,
+ "name": "순두부찌개",
+ "category": "SOUP",
+ "costPrice": 6200,
+ "salePrice": 5900,
+ "salePercent": 5,
+ "quantity": 4
+ }
+ ]
+ },
+ "isSuccess": true
+ }
+ """
+ )
+ )
+ )
+ ResponseEntity> getStoreMenus(
+ @Parameter(name = "storeId", in = ParameterIn.PATH, description = "가게 ID", example = "1", required = true)
+ @PathVariable Long storeId,
+ @Parameter(name = "lat", in = ParameterIn.QUERY, description = "사용자 위도", example = "37.468355", required = true)
+ @RequestParam("lat") Double lat,
+ @Parameter(name = "lng", in = ParameterIn.QUERY, description = "사용자 경도", example = "127.039073", required = true)
+ @RequestParam("lng") Double lng);
+}
diff --git a/src/main/java/com/example/Centralthon/domain/store/web/controller/StoreController.java b/src/main/java/com/example/Centralthon/domain/store/web/controller/StoreController.java
index c5bc02e..6ffff81 100644
--- a/src/main/java/com/example/Centralthon/domain/store/web/controller/StoreController.java
+++ b/src/main/java/com/example/Centralthon/domain/store/web/controller/StoreController.java
@@ -1,5 +1,6 @@
package com.example.Centralthon.domain.store.web.controller;
+import com.example.Centralthon.domain.order.web.controller.OrderApi;
import com.example.Centralthon.domain.store.service.StoreService;
import com.example.Centralthon.domain.store.web.dto.NearbyStoresRes;
import com.example.Centralthon.domain.store.web.dto.StoreMenusRes;
@@ -14,11 +15,12 @@
@RestController
@RequestMapping("/api/stores")
@RequiredArgsConstructor
-public class StoreController {
+public class StoreController implements StoreApi {
private final StoreService storeService;
// 근처 가게 위치 목록 조회
@GetMapping("")
+ @Override
public ResponseEntity>> nearbyStores(
@RequestParam("lat") Double lat,
@RequestParam("lng") Double lng){
@@ -30,6 +32,7 @@ public ResponseEntity>> nearbyStores(
// 가게 판매 메뉴 목록 조회
@GetMapping("/{storeId}/menus")
+ @Override
public ResponseEntity> getStoreMenus(
@PathVariable Long storeId,
@RequestParam("lat") Double lat,
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index a57e3d2..a24dd91 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -15,7 +15,7 @@ spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
# Swagger
-springdoc.swagger-ui.path=/swagger-ui.html
+springdoc.swagger-ui.path=/api/swagger-ui.html
springdoc.api-docs.path=/api-docs
springdoc.group-configs[0].group=default
springdoc.group-configs[0].paths-to-match=/**