diff --git a/src/main/java/com/assu/server/domain/admin/controller/AdminController.java b/src/main/java/com/assu/server/domain/admin/controller/AdminController.java index bc462d93..72bb3c31 100644 --- a/src/main/java/com/assu/server/domain/admin/controller/AdminController.java +++ b/src/main/java/com/assu/server/domain/admin/controller/AdminController.java @@ -4,6 +4,8 @@ import com.assu.server.domain.admin.service.AdminService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -35,6 +37,7 @@ public class AdminController { " - `partnerName` (String): 제휴업체 상호명\n" + " - `partnerUrl` (String): 제휴업체 프로필 이미지 URL (S3 주소)\n" + " - `partnerPhone` (String): 제휴업체 전화번호\n") + @ApiErrorCodeExamples(SwaggerErrorCodes.ADMIN_PARTNER_RECOMMEND) @GetMapping("/partner-recommend") public BaseResponse randomPartnerRecommend( @AuthenticationPrincipal PrincipalDetails pd diff --git a/src/main/java/com/assu/server/domain/admin/controller/StudentAdminController.java b/src/main/java/com/assu/server/domain/admin/controller/StudentAdminController.java index 9c64ec8b..746eca16 100644 --- a/src/main/java/com/assu/server/domain/admin/controller/StudentAdminController.java +++ b/src/main/java/com/assu/server/domain/admin/controller/StudentAdminController.java @@ -4,6 +4,8 @@ import com.assu.server.domain.admin.service.StudentAdminService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -28,6 +30,7 @@ public class StudentAdminController { description = "# [v1.0 (2025-09-02)](https://www.notion.so/_-24c1197c19ed8062be94fc08619b760f)\n" + "- 관리자(Admin) 권한으로 접근하여 현재까지의 총 누적 가입자 수를 조회합니다." ) + @ApiErrorCodeExamples(SwaggerErrorCodes.ADMIN_DASHBOARD_COUNT_ADMIN) @GetMapping public BaseResponse getCountAdmin( @AuthenticationPrincipal PrincipalDetails pd @@ -40,6 +43,7 @@ public BaseResponse getCountA description = "# [v1.0 (2025-09-02)](https://www.notion.so/_-24c1197c19ed805db80fca98c38849d1)\n" + "- 이번 달(매달 1일 초기화) 기준 신규 가입한 사용자 수를 조회합니다." ) + @ApiErrorCodeExamples(SwaggerErrorCodes.ADMIN_DASHBOARD_NEW_STUDENT_COUNT) @GetMapping("/new") public BaseResponse getNewStudentCountAdmin( @AuthenticationPrincipal PrincipalDetails pd @@ -52,6 +56,7 @@ public BaseResponse getNewStud description = "# [v1.0 (2025-09-02)](https://www.notion.so/_-24e1197c19ed80a283b1c336a1c3df72)\n" + "- 금일 제휴 서비스를 이용한 총 사용자 수를 조회합니다." ) + @ApiErrorCodeExamples(SwaggerErrorCodes.ADMIN_DASHBOARD_COUNT_USER) @GetMapping("/countUser") public BaseResponse getCountUser( @AuthenticationPrincipal PrincipalDetails pd @@ -64,6 +69,7 @@ public BaseResponse getCoun description = "# [v1.0 (2025-09-02)](https://www.notion.so/_1-2ef1197c19ed8010a49ce6313d137b4f)\n" + "- 제휴 이용 횟수가 가장 많은 1위 업체의 정보를 조회합니다." ) + @ApiErrorCodeExamples(SwaggerErrorCodes.ADMIN_DASHBOARD_TOP_USAGE) @GetMapping("/top") public BaseResponse getTopUsage( @AuthenticationPrincipal PrincipalDetails pd @@ -76,6 +82,7 @@ public BaseResponse getTopUsage( description = "# [v1.0 (2025-09-02)](https://www.notion.so/_-24e1197c19ed802b92eff5d4dc4dbe82)\n" + "- 모든 제휴 업체의 누적 사용 현황을 사용량 내림차순 리스트로 반환합니다." ) + @ApiErrorCodeExamples(SwaggerErrorCodes.ADMIN_DASHBOARD_USAGE_LIST) @GetMapping("/usage") public BaseResponse getUsageList( @AuthenticationPrincipal PrincipalDetails pd diff --git a/src/main/java/com/assu/server/domain/appreview/controller/AppReviewController.java b/src/main/java/com/assu/server/domain/appreview/controller/AppReviewController.java index 6b06b7ca..1675bf90 100644 --- a/src/main/java/com/assu/server/domain/appreview/controller/AppReviewController.java +++ b/src/main/java/com/assu/server/domain/appreview/controller/AppReviewController.java @@ -4,6 +4,8 @@ import com.assu.server.domain.appreview.service.AppReviewService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; @@ -38,6 +40,7 @@ public class AppReviewController { "\n**Response:**\n" + " - 성공 시 200(OK)과 성공 메시지 반환" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.APP_REVIEW_CREATE) @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) public BaseResponse createAppReview( @io.swagger.v3.oas.annotations.parameters.RequestBody( diff --git a/src/main/java/com/assu/server/domain/auth/controller/AuthController.java b/src/main/java/com/assu/server/domain/auth/controller/AuthController.java index 8e508ceb..77f715d2 100644 --- a/src/main/java/com/assu/server/domain/auth/controller/AuthController.java +++ b/src/main/java/com/assu/server/domain/auth/controller/AuthController.java @@ -25,6 +25,8 @@ import com.assu.server.domain.common.entity.enums.University; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -66,6 +68,7 @@ public class AuthController { "\n**Response:**\n" + " - 성공 시 200(OK)과 성공 메시지 반환" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_PHONE_SEND_CODE) @PostMapping("/phone-verification/check-and-send") public BaseResponse checkPhoneAvailabilityAndSendAuthNumber( @io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -95,6 +98,7 @@ public BaseResponse checkPhoneAvailabilityAndSendAuthNumber( "\n**Response:**\n" + " - 성공 시 200(OK)과 성공 메시지 반환" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_PHONE_VERIFY_CODE) @PostMapping("/phone-verification/verify") public BaseResponse checkAuthNumber( @io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -128,6 +132,7 @@ public BaseResponse checkAuthNumber( " - 성공 시 200(OK)과 사용 가능 메시지 반환\n" + " - 중복 시 404(NOT_FOUND)와 에러 메시지 반환" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_EMAIL_CHECK) @PostMapping("/email-verification/check") public BaseResponse checkEmailAvailability( @io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -175,6 +180,7 @@ public BaseResponse checkEmailAvailability( " - `department` (String): 단과대 (한글명)\n" + " - `major` (String): 전공/학과 (한글명)" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_SIGNUP_STUDENT) @PostMapping(value = "/students/signup", consumes = MediaType.APPLICATION_JSON_VALUE) public BaseResponse signupStudent( @io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -245,6 +251,7 @@ public BaseResponse signupStudent( " - `department` (String): null (Partner는 해당 없음)\n" + " - `major` (String): null (Partner는 해당 없음)" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_SIGNUP_PARTNER) @PostMapping(value = "/partners/signup", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public BaseResponse signupPartner( @RequestPart("request") @@ -319,6 +326,7 @@ public BaseResponse signupPartner( " - `department` (String): 단과대 (한글명)\n" + " - `major` (String): 전공/학과 (한글명)" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_SIGNUP_ADMIN) @PostMapping(value = "/admins/signup", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public BaseResponse signupAdmin( @RequestPart("request") @@ -373,6 +381,7 @@ public BaseResponse signupAdmin( " - 403(FORBIDDEN): `BACKOFFICE4003` — BACKOFFICE 계정은 `/auth/backoffice/login` 사용\n" + " - 401(UNAUTHORIZED): 이메일/비밀번호 불일치" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_LOGIN_COMMON) @PostMapping(value = "/commons/login", consumes = MediaType.APPLICATION_JSON_VALUE) public BaseResponse loginCommon( @io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -414,6 +423,7 @@ public BaseResponse loginCommon( " - `department` (String): 단과대 (한글명)\n" + " - `major` (String): 전공/학과 (한글명)" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_LOGIN_STUDENT) @PostMapping(value = "/students/login", consumes = MediaType.APPLICATION_JSON_VALUE) public BaseResponse loginStudent( @io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -452,6 +462,7 @@ public BaseResponse loginStudent( " - `newAccess` (String): 새로운 액세스 토큰\n" + " - `newRefresh` (String): 새로운 리프레시 토큰" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_TOKEN_REFRESH) @PostMapping("/tokens/refresh") public BaseResponse refreshToken( @Parameter( @@ -475,6 +486,7 @@ public BaseResponse refreshToken( "- 처리: Refresh 무효화(선택), Access 블랙리스트 등록.\n" + "- 성공 시 200(OK)." ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_LOGOUT) @PostMapping("/logout") public BaseResponse logout( @Parameter( @@ -513,6 +525,7 @@ public BaseResponse logout( " - `yearSemester` (String): 학년/학기\n" + " - `major` (Major enum): 전공/학과" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_SSU_VERIFY) @PostMapping(value = "/students/ssu-verify", consumes = MediaType.APPLICATION_JSON_VALUE) public BaseResponse ssuAuth( @io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -545,6 +558,7 @@ public BaseResponse ssuAuth( " - 성공 시 200(OK)과 성공 메시지 반환\n" + " - 유예기간 내 재로그인 및 재가입 시 계정 복구" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.AUTH_WITHDRAW) @PatchMapping("/withdraw") public BaseResponse withdrawMember( @Parameter( diff --git a/src/main/java/com/assu/server/domain/auth/controller/BackofficeAuthController.java b/src/main/java/com/assu/server/domain/auth/controller/BackofficeAuthController.java index b02044bd..5985a34d 100644 --- a/src/main/java/com/assu/server/domain/auth/controller/BackofficeAuthController.java +++ b/src/main/java/com/assu/server/domain/auth/controller/BackofficeAuthController.java @@ -6,6 +6,8 @@ import com.assu.server.domain.auth.service.BackofficeAuthService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.enums.ParameterIn; @@ -51,6 +53,7 @@ public class BackofficeAuthController { " - 403(FORBIDDEN): BACKOFFICE 역할이 아닌 계정\n" + " - 401(UNAUTHORIZED): 이메일 또는 비밀번호 불일치" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_AUTH_LOGIN) @PostMapping(value = "/login", consumes = MediaType.APPLICATION_JSON_VALUE) public BaseResponse login( @io.swagger.v3.oas.annotations.parameters.RequestBody( @@ -85,6 +88,7 @@ public BaseResponse login( " - `newRefresh` (String): 새로운 리프레시 토큰\n" + " - 401(UNAUTHORIZED): audience 불일치 또는 유효하지 않은 Refresh Token" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_AUTH_REFRESH) @PostMapping("/tokens/refresh") public BaseResponse refresh( @Parameter( diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeAdminController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeAdminController.java index fe89820a..99427f2c 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeAdminController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeAdminController.java @@ -6,6 +6,8 @@ import com.assu.server.domain.backoffice.service.BackofficeMemberService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -38,6 +40,7 @@ public class BackofficeAdminController { "- 403(FORBIDDEN): BACKOFFICE 권한 없음\n" + "- 404(NOT_FOUND): Admin이 아니거나 인감 이미지 없음" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_ADMIN_GET_SIGN_IMAGE) @GetMapping("/{memberId}/sign-image") public BaseResponse getSignImageUrl( @Parameter(description = "Admin 회원 ID") @PathVariable Long memberId @@ -72,6 +75,7 @@ public BaseResponse fetchAdmin() { } @BackofficeAudited(action = "ADMIN_CREATE", targetId = "#req.email") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_ADMIN_CREATE) @Operation( summary = "학생회 계정 임의 추가 API", description = "인감 정보나 전화번호 없이 백오피스에서 임의로 학생회 계정을 추가합니다.\n\n" + @@ -103,6 +107,7 @@ public BaseResponse createAdmin( } @BackofficeAudited(action = "ADMIN_UPDATE", targetId = "#adminId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_ADMIN_UPDATE) @Operation( summary = "학생회 계정 임의 수정 API", description = "학생회(Admin) 계정 정보를 수정합니다. 입력된 필드만 반영됩니다.\n\n" + @@ -143,6 +148,7 @@ public BaseResponse updateAdmin( } @BackofficeAudited(action = "ADMIN_DELETE", targetId = "#adminId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_ADMIN_DELETE) @Operation( summary = "학생회 계정 임의 삭제 API", description = "학생회(Admin) 계정과 이에 연관된 모든 데이터(Member, CommonAuth)를 영구 삭제합니다.\n\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeChatController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeChatController.java index f6608eec..e8903860 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeChatController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeChatController.java @@ -5,6 +5,8 @@ import com.assu.server.domain.backoffice.service.BackofficeChatBlockService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; @@ -22,6 +24,7 @@ public class BackofficeChatController { private final BackofficeChatBlockService backofficeChatBlockService; @BackofficeAudited(action = "CHAT_BLOCK_BETWEEN", targetId = "#request.blockerId() + '-' + #request.blockedId()") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_CHAT_BLOCK_BETWEEN) @Operation( summary = "두 멤버 간 채팅 차단 API", description = "- 특정 두 멤버 사이의 채팅을 차단합니다.\n" + @@ -39,6 +42,7 @@ public BaseResponse block } @BackofficeAudited(action = "CHAT_UNBLOCK_BETWEEN", targetId = "#memberAId + '-' + #memberBId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_CHAT_UNBLOCK_BETWEEN) @Operation( summary = "두 멤버 간 채팅 차단 해제 API", description = "- 특정 두 멤버 사이의 채팅 차단을 해제합니다.\n" + @@ -57,6 +61,7 @@ public BaseResponse unblo } @BackofficeAudited(action = "CHAT_BLOCK_MEMBER", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_CHAT_BLOCK_MEMBER) @Operation( summary = "멤버 채팅 전체 차단 API", description = "- 특정 멤버의 채팅 기능 자체를 차단합니다.\n" + @@ -73,6 +78,7 @@ public BaseResponse blockMemb } @BackofficeAudited(action = "CHAT_UNBLOCK_MEMBER", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_CHAT_UNBLOCK_MEMBER) @Operation( summary = "멤버 채팅 전체 차단 해제 API", description = "- 특정 멤버의 채팅 전체 차단을 해제합니다.\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeDevSyncController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeDevSyncController.java index a6f4bf7d..62df5a5b 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeDevSyncController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeDevSyncController.java @@ -5,6 +5,8 @@ import com.assu.server.domain.backoffice.service.BackofficeDevSyncService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -23,6 +25,7 @@ public class BackofficeDevSyncController { private final BackofficeDevSyncService backofficeDevSyncService; @BackofficeAudited(action = "DEV_SYNC") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_DEV_SYNC) @Operation( summary = "Prod DB → Dev DB 동기화 API", description = "# [v1.0 (2026-10-04)]\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeHomeCurationController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeHomeCurationController.java index 2ef7775f..8b5e2f51 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeHomeCurationController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeHomeCurationController.java @@ -16,6 +16,8 @@ import com.assu.server.domain.backoffice.service.BackofficeHomeCurationService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -44,6 +46,7 @@ public BaseResponse getHomeCuration() { } @BackofficeAudited(action = "HOME_CURATION_UPDATE") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_HOME_CURATION_UPDATE) @Operation( summary = "전체 큐레이션 및 추천 업체 직접 저장 API (백오피스용)", description = "상단 추천 업체 및 2개 그룹(각 그룹당 2개 매장)을 직접 지정하여 저장합니다.\n\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeInquiryController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeInquiryController.java index 95567908..0e19bf5f 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeInquiryController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeInquiryController.java @@ -6,6 +6,8 @@ import com.assu.server.domain.inquiry.service.BackofficeInquiryService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import com.assu.server.domain.common.dto.PageResponseDTO; @@ -31,6 +33,7 @@ public class BackofficeInquiryController { private final BackofficeInquiryService backofficeInquiryService; + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_INQUIRY_LIST) @Operation( summary = "운영자 전체 문의 목록 조회 API", description = "# [v1.1 (2026-07-04)]\n" + @@ -61,6 +64,7 @@ public BaseResponse> listAllInquiries( return BaseResponse.onSuccess(SuccessStatus._OK, backofficeInquiryService.getInquiries(status, keyword, page, size)); } + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_INQUIRY_DETAIL) @Operation( summary = "운영자 문의 상세 조회 API", description = "# [v1.0 (2026-06-25)]\n" + @@ -82,6 +86,7 @@ public BaseResponse getInquiry( } @BackofficeAudited(action = "INQUIRY_ANSWER", targetId = "#inquiryId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_INQUIRY_ANSWER) @Operation( summary = "운영자 문의 답변 API", description = "# [v1.0 (2025-09-02)](https://www.notion.so/24e1197c19ed8064808fcca568b8912a?source=copy_link)\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeMemberController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeMemberController.java index 6567a0a7..b9de8f6f 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeMemberController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeMemberController.java @@ -9,6 +9,8 @@ import com.assu.server.domain.common.enums.UserRole; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -100,6 +102,7 @@ public BaseResponse> listDeletedMemb "- 403(FORBIDDEN): BACKOFFICE 권한 없음\n" + "- 404(NOT_FOUND): 존재하지 않는 회원 ID" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_MEMBER_GET_DETAIL) @GetMapping("/{memberId}") public BaseResponse getMemberDetail( @Parameter(description = "회원 ID") @PathVariable Long memberId @@ -111,6 +114,7 @@ public BaseResponse getMemberDetail( } @BackofficeAudited(action = "MEMBER_APPROVE", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_MEMBER_APPROVE) @Operation( summary = "회원 가입 승인 API", description = "# [v1.0 (2026-07-03)]\n" + @@ -134,6 +138,7 @@ public BaseResponse approveMember(@PathVariable Long } @BackofficeAudited(action = "MEMBER_REJECT", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_MEMBER_REJECT) @Operation( summary = "회원 가입 거절 API", description = "# [v1.0 (2026-07-03)]\n" + @@ -154,6 +159,7 @@ public BaseResponse rejectMember(@PathVariable Long } @BackofficeAudited(action = "MEMBER_FORCE_WITHDRAW", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_MEMBER_FORCE_WITHDRAW) @Operation( summary = "회원 강제 탈퇴 API", description = "# [v1.1 (2026-09-25)]\n" + @@ -177,6 +183,7 @@ public BaseResponse forceWithdrawMember(@PathVariable Long memberId) { } @BackofficeAudited(action = "MEMBER_RESTORE", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_MEMBER_RESTORE) @Operation( summary = "탈퇴 회원 복구 API", description = "# [v1.0 (2026-07-03)]\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeNotificationController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeNotificationController.java index 79ee2f4d..34758e3d 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeNotificationController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeNotificationController.java @@ -9,6 +9,8 @@ import com.assu.server.domain.common.dto.PageResponseDTO; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -29,6 +31,7 @@ public class BackofficeNotificationController { private final BackofficeNotificationService backofficeNotificationService; @BackofficeAudited(action = "PUSH_SEND", targetId = "#request.receiverId()") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_NOTIFICATION_PUSH_SEND) @Operation( summary = "운영자 수동 푸시 알림 전송 API", description = "# [v1.1 (2026-07-04)]\n" + @@ -56,6 +59,7 @@ public BaseResponse sendPush( return BaseResponse.onSuccess(SuccessStatus._OK, null); } + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_NOTIFICATION_PUSH_LOG_LIST) @Operation( summary = "푸시 발송 이력 조회 API", description = "# [v1.1 (2026-07-04)]\n" + @@ -82,6 +86,7 @@ public BaseResponse> getPushLogs( return BaseResponse.onSuccess(SuccessStatus._OK, backofficeNotificationService.getPushLogs(keyword, page, size)); } + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_NOTIFICATION_OUTBOX_FAILED_LIST) @Operation( summary = "전송 실패 알림 목록 조회 API", description = "# [v1.0 (2026-06-25)]\n" + @@ -106,6 +111,7 @@ public BaseResponse> getFailedOutbo } @BackofficeAudited(action = "PUSH_RETRY", targetId = "#outboxId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_NOTIFICATION_OUTBOX_RETRY) @Operation( summary = "실패 알림 수동 재전송 API", description = "# [v1.0 (2026-06-25)]\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeOperatorController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeOperatorController.java index 4cb0dfa1..139616eb 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeOperatorController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeOperatorController.java @@ -6,6 +6,8 @@ import com.assu.server.domain.backoffice.service.BackofficeOperatorService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; @@ -29,6 +31,7 @@ public class BackofficeOperatorController { private final BackofficeOperatorService backofficeOperatorService; @BackofficeAudited(action = "OPERATOR_CREATE") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_OPERATOR_CREATE) @Operation( summary = "백오피스 운영자 생성 API", description = "# [v1.0 (2026-06-23)]\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficePaperController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficePaperController.java index 1777caa0..9a31958d 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficePaperController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficePaperController.java @@ -21,6 +21,8 @@ import com.assu.server.domain.partnership.dto.WritePartnershipResponseDTO; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -73,6 +75,7 @@ public BaseResponse> getPapers( } @BackofficeAudited(action = "PAPER_CREATE", targetId = "#req.adminId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PAPER_CREATE) @Operation( summary = "임의의 제휴 계약서 생성 API (백오피스용)", description = "운영자가 임의의 제휴 계약서를 생성(빈 제휴 계약서)합니다.\n\n" + @@ -94,6 +97,7 @@ public BaseResponse createPaper( } @BackofficeAudited(action = "PAPER_CONTENT_ADD", targetId = "#paperId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PAPER_CONTENT_ADD) @Operation( summary = "제휴 계약서 내용(옵션) 추가 API (백오피스용)", description = "생성되어 있는 빈 제휴 계약서에 구체적인 제휴 혜택/옵션 및 Goods를 추가합니다.\n\n" + @@ -125,6 +129,7 @@ public BaseResponse addPaperContents( } @BackofficeAudited(action = "PAPER_APPROVE", targetId = "#paperId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PAPER_APPROVE) @Operation( summary = "제휴 계약서 승인 API (백오피스용)", description = "제휴 계약서를 승인하여 제휴 상태를 ACTIVE로 변경합니다.\n\n" + @@ -142,6 +147,7 @@ public BaseResponse approvePaper( } @BackofficeAudited(action = "PAPER_REJECT", targetId = "#paperId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PAPER_REJECT) @Operation( summary = "제휴 계약서 거부 API (백오피스용)", description = "제휴 계약서를 거부하여 제휴 상태를 INACTIVE로 변경합니다.\n\n" + @@ -159,6 +165,7 @@ public BaseResponse rejectPaper( } @BackofficeAudited(action = "PAPER_EXPIRE", targetId = "#paperId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PAPER_EXPIRE) @Operation( summary = "제휴 계약서 만료 API (백오피스용)", description = "제휴 계약서를 강제 만료하여 제휴 상태를 INACTIVE로 변경합니다.\n\n" + diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficePartnerController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficePartnerController.java index 722efd3b..e912f7ef 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficePartnerController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficePartnerController.java @@ -10,6 +10,8 @@ import com.assu.server.domain.backoffice.service.BackofficeMemberService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -54,6 +56,7 @@ public class BackofficePartnerController { "- 403(FORBIDDEN): BACKOFFICE 권한 없음\n" + "- 404(NOT_FOUND): Partner가 아니거나 사업자등록증 없음" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PARTNER_GET_LICENSE) @GetMapping("/{memberId}/license") public BaseResponse getLicenseUrl( @Parameter(description = "Partner 회원 ID") @PathVariable Long memberId @@ -65,6 +68,7 @@ public BaseResponse getLicenseUrl( } @BackofficeAudited(action = "PARTNER_LICENSE_VERIFY", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PARTNER_VERIFY_LICENSE) @Operation( summary = "사업자등록증 검증 API", description = "# [v1.0 (2026-07-03)]\n" + @@ -85,6 +89,7 @@ public BaseResponse verifyLicense(@PathVariable Long } @BackofficeAudited(action = "PARTNER_PROFILE_IMAGE_UPDATE", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PARTNER_UPDATE_PROFILE_IMAGE) @Operation( summary = "제휴업체 프로필 이미지 업로드 API", description = "# [v1.0 (2026-10-04)]\n" + @@ -115,6 +120,7 @@ public BaseResponse updateProfileImage( } @BackofficeAudited(action = "PARTNER_PROFILE_IMAGE_DELETE", targetId = "#memberId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PARTNER_DELETE_PROFILE_IMAGE) @Operation( summary = "제휴업체 프로필 이미지 삭제 API", description = "# [v1.0 (2026-10-04)]\n" + @@ -137,6 +143,7 @@ public BaseResponse deleteProfileImage( } @BackofficeAudited(action = "PARTNER_BATCH_SIGNUP") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_PARTNER_BATCH_SIGNUP) @Operation( summary = "제휴업체 단체 회원가입 API", description = "이메일, 비밀번호, 업체명, 도로명 주소, 위도, 경도 목록을 받아 제휴업체 계정들을 일괄 생성합니다." diff --git a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeReportController.java b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeReportController.java index 386b1ed0..44fe7d0c 100644 --- a/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeReportController.java +++ b/src/main/java/com/assu/server/domain/backoffice/controller/BackofficeReportController.java @@ -16,6 +16,8 @@ import com.assu.server.domain.backoffice.service.BackofficeReportService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -42,6 +44,7 @@ public BaseResponse> getReports( } @BackofficeAudited(action = "REPORT_DETAIL_READ", targetId = "#reportId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_REPORT_DETAIL) @Operation(summary = "신고 상세 조회 API (백오피스용)", description = "특정 신고 ID 기준 상세 내용을 조회합니다.") @GetMapping("/reports/{reportId}") public BaseResponse getReportDetail( @@ -51,6 +54,7 @@ public BaseResponse getReportDetail( } @BackofficeAudited(action = "REPORT_STATUS_UPDATE", targetId = "#reportId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_REPORT_STATUS_UPDATE) @Operation(summary = "신고 상태 변경 및 기본 처리 API (백오피스용)", description = "신고의 처리 상태를 변경합니다.") @PatchMapping("/reports/{reportId}/status") public BaseResponse updateReportStatus( @@ -62,6 +66,7 @@ public BaseResponse updateReportStatus( } @BackofficeAudited(action = "REVIEW_DELETE", targetId = "#reviewId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_REVIEW_DELETE) @Operation( summary = "리뷰 소프트 삭제 API", description = "- 리뷰를 삭제 처리합니다 (status → DELETED).\n" + @@ -78,6 +83,7 @@ public BaseResponse deleteReview( } @BackofficeAudited(action = "SUGGESTION_DELETE", targetId = "#suggestionId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_SUGGESTION_DELETE) @Operation( summary = "건의글 소프트 삭제 API", description = "- 건의글을 삭제 처리합니다 (status → DELETED).\n" + @@ -94,6 +100,7 @@ public BaseResponse deleteSuggestion( } @BackofficeAudited(action = "REPORT_REJECT", targetId = "#reportId") + @ApiErrorCodeExamples(SwaggerErrorCodes.BACKOFFICE_REPORT_REJECT) @Operation( summary = "신고 기각 API", description = "- 신고를 기각 처리합니다 (ReportStatus → REJECTED).\n" + diff --git a/src/main/java/com/assu/server/domain/certification/controller/CertificationController.java b/src/main/java/com/assu/server/domain/certification/controller/CertificationController.java index c67b3e2d..3ac5cfa1 100644 --- a/src/main/java/com/assu/server/domain/certification/controller/CertificationController.java +++ b/src/main/java/com/assu/server/domain/certification/controller/CertificationController.java @@ -15,6 +15,8 @@ import com.assu.server.domain.certification.service.CertificationService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; @@ -57,6 +59,7 @@ public ResponseEntity> getSessionId( } @DeleteMapping("/certification/session/{sessionId}") + @ApiErrorCodeExamples(SwaggerErrorCodes.CERTIFICATION_EXPIRE_SESSION) @Operation( summary = "그룹 인증 세션 만료 API", description = "세션 생성자만 인증 세션을 즉시 만료시킬 수 있습니다. 만료 후 해당 세션으로 들어오는 인증 요청은 거절됩니다." @@ -71,6 +74,7 @@ public ResponseEntity> expireSession( } @PostMapping("/certification/personal") + @ApiErrorCodeExamples(SwaggerErrorCodes.CERTIFICATION_PERSONAL) @Operation( summary = "개인 인증 요청 API", description = diff --git a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java index 4c5087c4..8d436031 100644 --- a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java +++ b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java @@ -6,6 +6,8 @@ import com.assu.server.domain.chat.service.ChatService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -38,6 +40,7 @@ public class ChatController { "- partnerId (Long, required) 제휴업체 ID\n" ) @PreAuthorize("hasAnyRole('ADMIN', 'PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.CHAT_CREATE_ROOM) @PostMapping("/rooms") public BaseResponse createChatRoom( @AuthenticationPrincipal PrincipalDetails pd, @@ -109,6 +112,7 @@ public BaseResponse readMessage( "- roomId (Long, required): 채팅방 ID\n" ) @PreAuthorize("hasAnyRole('ADMIN', 'PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.CHAT_GET_HISTORY) @GetMapping("/rooms/{roomId}/messages") public BaseResponse getChatHistory( @AuthenticationPrincipal PrincipalDetails pd, @@ -128,6 +132,7 @@ public BaseResponse getChatHistory( "- roomId (Long, required): 채팅방 ID\n" ) @PreAuthorize("hasAnyRole('ADMIN', 'PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.CHAT_LEAVE_ROOM) @DeleteMapping("/rooms/{roomId}/leave") public BaseResponse leaveChattingRoom( @AuthenticationPrincipal PrincipalDetails pd, @@ -146,6 +151,7 @@ public BaseResponse leaveChattingR "- opponentId (Long, required): 상대방 ID\n" ) @PreAuthorize("hasAnyRole('ADMIN', 'PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.CHAT_BLOCK_MEMBER) @PostMapping("/block") public BaseResponse block( @AuthenticationPrincipal PrincipalDetails pd, @@ -163,6 +169,7 @@ public BaseResponse block( "- opponentId (Long, required): 상대방 ID\n" ) @PreAuthorize("hasAnyRole('ADMIN', 'PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.CHAT_CHECK_BLOCK) @GetMapping("/check/block/{opponentId}") public BaseResponse checkBlock( @AuthenticationPrincipal PrincipalDetails pd, @@ -180,6 +187,7 @@ public BaseResponse checkBlock( "- opponentId (Long, required): 상대방 ID\n" ) @PreAuthorize("hasAnyRole('ADMIN', 'PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.CHAT_UNBLOCK_MEMBER) @DeleteMapping("/unblock") public BaseResponse unblock( @AuthenticationPrincipal PrincipalDetails pd, @@ -195,6 +203,7 @@ public BaseResponse unblock( "- 차단한 대상을 조회합니다.\n" ) @PreAuthorize("hasAnyRole('ADMIN', 'PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.CHAT_GET_BLOCK_LIST) @GetMapping("/block-list") public BaseResponse> getBlockList( @AuthenticationPrincipal PrincipalDetails pd diff --git a/src/main/java/com/assu/server/domain/deviceToken/controller/DeviceTokenController.java b/src/main/java/com/assu/server/domain/deviceToken/controller/DeviceTokenController.java index ee26554e..4d415327 100644 --- a/src/main/java/com/assu/server/domain/deviceToken/controller/DeviceTokenController.java +++ b/src/main/java/com/assu/server/domain/deviceToken/controller/DeviceTokenController.java @@ -3,6 +3,8 @@ import com.assu.server.domain.deviceToken.service.DeviceTokenService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -33,6 +35,7 @@ public class DeviceTokenController { "- 401(UNAUTHORIZED): 인증되지 않은 사용자\n" + "- 409(CONFLICT): 이미 등록된 토큰" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.DEVICE_TOKEN_REGISTER) @PostMapping public BaseResponse register(@AuthenticationPrincipal PrincipalDetails pd, @RequestParam String token) { @@ -52,6 +55,7 @@ public BaseResponse register(@AuthenticationPrincipal PrincipalDetails pd, "- 403(FORBIDDEN): 다른 사용자의 토큰 해제 시도\n" + "- 404(NOT_FOUND): 존재하지 않는 토큰 ID" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.DEVICE_TOKEN_UNREGISTER) @DeleteMapping("/{tokenId}") public BaseResponse unregister(@AuthenticationPrincipal PrincipalDetails pd, @PathVariable("tokenId") Long tokenId) { diff --git a/src/main/java/com/assu/server/domain/inquiry/controller/InquiryController.java b/src/main/java/com/assu/server/domain/inquiry/controller/InquiryController.java index f593316f..0f347b68 100644 --- a/src/main/java/com/assu/server/domain/inquiry/controller/InquiryController.java +++ b/src/main/java/com/assu/server/domain/inquiry/controller/InquiryController.java @@ -7,6 +7,8 @@ import com.assu.server.domain.inquiry.service.InquiryService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; @@ -43,6 +45,7 @@ public class InquiryController { "- 400(BAD_REQUEST): 필수 필드 누락 또는 잘못된 이메일 형식\n" + "- 401(UNAUTHORIZED): 인증되지 않은 사용자" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.INQUIRY_CREATE) @PostMapping public BaseResponse create( @AuthenticationPrincipal PrincipalDetails pd, @@ -65,6 +68,7 @@ public BaseResponse create( "- 400(BAD_REQUEST): 잘못된 페이지 번호 또는 상태 값\n" + "- 401(UNAUTHORIZED): 인증되지 않은 사용자" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.INQUIRY_LIST) @GetMapping public BaseResponse> list( @AuthenticationPrincipal PrincipalDetails pd, @@ -88,6 +92,7 @@ public BaseResponse> list( "- 403(FORBIDDEN): 다른 사용자의 문의 접근 시도\n" + "- 404(NOT_FOUND): 존재하지 않는 문의 ID" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.INQUIRY_GET) @GetMapping("/{inquiryId}") public BaseResponse get( @AuthenticationPrincipal PrincipalDetails pd, diff --git a/src/main/java/com/assu/server/domain/member/controller/MemberController.java b/src/main/java/com/assu/server/domain/member/controller/MemberController.java index d2dc56cd..55a7dca7 100644 --- a/src/main/java/com/assu/server/domain/member/controller/MemberController.java +++ b/src/main/java/com/assu/server/domain/member/controller/MemberController.java @@ -4,6 +4,8 @@ import com.assu.server.domain.member.service.ProfileImageService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -42,6 +44,7 @@ public class MemberController { "- 401(UNAUTHORIZED): 인증되지 않은 사용자\n" + "- 500(INTERNAL_SERVER_ERROR): S3 업로드 실패" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.MEMBER_UPLOAD_PROFILE_IMAGE) @PutMapping(value = "/me/profile-image", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public BaseResponse uploadOrReplaceProfileImage( @AuthenticationPrincipal PrincipalDetails pd, @@ -72,6 +75,7 @@ public BaseResponse uploadOrReplaceProfileImage( "- 401(UNAUTHORIZED): 인증되지 않은 사용자\n" + "- 500(INTERNAL_SERVER_ERROR): S3 presigned URL 생성 실패" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.MEMBER_GET_PROFILE_IMAGE) @GetMapping("/me/profile-image") public BaseResponse getProfileImage( @AuthenticationPrincipal PrincipalDetails pd @@ -92,6 +96,7 @@ public BaseResponse getProfileImage( "- 404(NOT_FOUND): 삭제할 프로필 이미지가 없음\n" + "- 500(INTERNAL_SERVER_ERROR): S3 삭제 실패" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.MEMBER_DELETE_PROFILE_IMAGE) @DeleteMapping("/me/profile-image") public BaseResponse deleteProfileImage( @AuthenticationPrincipal PrincipalDetails pd diff --git a/src/main/java/com/assu/server/domain/notification/controller/NotificationController.java b/src/main/java/com/assu/server/domain/notification/controller/NotificationController.java index 81429900..cdd44b54 100644 --- a/src/main/java/com/assu/server/domain/notification/controller/NotificationController.java +++ b/src/main/java/com/assu/server/domain/notification/controller/NotificationController.java @@ -6,6 +6,8 @@ import com.assu.server.domain.notification.service.NotificationQueryService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -40,6 +42,7 @@ public class NotificationController { "- 400(BAD_REQUEST): 잘못된 상태 값 또는 페이지 번호\n" + "- 401(UNAUTHORIZED): 인증되지 않은 사용자" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.NOTIFICATION_LIST) @GetMapping public BaseResponse> list( @AuthenticationPrincipal PrincipalDetails pd, @@ -65,6 +68,7 @@ public BaseResponse> list( "- 404(NOT_FOUND): 존재하지 않는 알림 ID\n" + "- 409(CONFLICT): 이미 읽음 처리된 알림" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.NOTIFICATION_MARK_READ) @PostMapping("/{notificationId}/read") public BaseResponse markRead(@AuthenticationPrincipal PrincipalDetails pd, @PathVariable("notificationId") Long notificationId) throws AccessDeniedException { @@ -88,6 +92,7 @@ public BaseResponse markRead(@AuthenticationPrincipal PrincipalDetails p "- 404(NOT_FOUND): 존재하지 않는 멤버 ID 또는 디바이스 토큰 없음\n" + "- 500(INTERNAL_SERVER_ERROR): FCM 전송 실패" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.NOTIFICATION_QUEUE) @PostMapping("/queue") public BaseResponse queue(@Valid @RequestBody QueueNotificationRequestDTO req) { notificationCommandService.queue(req); @@ -108,6 +113,7 @@ public BaseResponse queue(@Valid @RequestBody QueueNotificationRequestDT "- 400(BAD_REQUEST): 지원하지 않는 알림 유형\n" + "- 401(UNAUTHORIZED): 인증되지 않은 사용자" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.NOTIFICATION_TOGGLE) @PutMapping("/{type}") public BaseResponse toggle( @AuthenticationPrincipal PrincipalDetails pd, @@ -127,6 +133,7 @@ public BaseResponse toggle( "- 각 알림 유형별 true/false 값 포함\n" + "- 401(UNAUTHORIZED): 인증되지 않은 사용자" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.NOTIFICATION_GET_SETTINGS) @GetMapping("/settings") public BaseResponse getSettings( @AuthenticationPrincipal PrincipalDetails pd diff --git a/src/main/java/com/assu/server/domain/partner/controller/PartnerController.java b/src/main/java/com/assu/server/domain/partner/controller/PartnerController.java index 589b34a1..347e7164 100644 --- a/src/main/java/com/assu/server/domain/partner/controller/PartnerController.java +++ b/src/main/java/com/assu/server/domain/partner/controller/PartnerController.java @@ -4,6 +4,8 @@ import com.assu.server.domain.partner.service.PartnerService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -33,6 +35,7 @@ public class PartnerController { " - `adminName` (String): 관리자 상호명\n" + " - `adminUrl` (String): 관리자 프로필 이미지 URL (S3 주소)\n" + " - `adminPhone` (String): 관리자 전화번호\n") + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNER_RANDOM_ADMIN_RECOMMEND) @GetMapping("/admin-recommend") public BaseResponse randomAdminRecommend( @AuthenticationPrincipal PrincipalDetails pd diff --git a/src/main/java/com/assu/server/domain/partnership/controller/PartnershipController.java b/src/main/java/com/assu/server/domain/partnership/controller/PartnershipController.java index 7db7c61a..5122540f 100644 --- a/src/main/java/com/assu/server/domain/partnership/controller/PartnershipController.java +++ b/src/main/java/com/assu/server/domain/partnership/controller/PartnershipController.java @@ -4,6 +4,8 @@ import com.assu.server.domain.partnership.service.PartnershipService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -35,6 +37,7 @@ public class PartnershipController { private final PartnershipService partnershipService; @PostMapping("/usage") + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_RECORD_USAGE) @Operation( summary = "제휴 사용내역 기록 API", description = "# [v1.0 (2025-12-23)](https://clumsy-seeder-416.notion.site/2681197c19ed8052804eddd5a1f3ce96?source=copy_link)\n" + @@ -63,6 +66,7 @@ public ResponseEntity> finalPartnershipRequest( return ResponseEntity.ok(BaseResponse.onSuccess(SuccessStatus.USER_PAPER_REQUEST_SUCCESS, null)); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_CREATE_DRAFT) @Operation( summary = "제휴 제안서 초안 생성 API", description = "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed8043a511cc8ea005d5b4)\n" + @@ -83,6 +87,7 @@ public BaseResponse createDraftPartnership( return BaseResponse.onSuccess(SuccessStatus._OK, partnershipService.createDraftPartnership(request, pd.getId())); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_CREATE_MANUAL) @Operation( summary = "제휴 제안서 수동 등록 API", description = "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2591197c19ed804785d9f58f95223048)\n" + @@ -164,6 +169,7 @@ public BaseResponse createManualPartnership( return BaseResponse.onSuccess(SuccessStatus._OK, partnershipService.createManualPartnership(request, pd.getId(), contractImage)); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_UPDATE) @Operation( summary = "제휴 제안서 내용 수정 API", description = "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2371197c19ed80aa8468d2377ef8eac2)\n" + @@ -219,6 +225,7 @@ public BaseResponse updatePartnership( return BaseResponse.onSuccess(SuccessStatus._OK, partnershipService.updatePartnership(request, pd.getId())); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_UPDATE_STATUS) @Operation( summary = "제휴 상태 업데이트 API", description = "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/SUSPEND-ACTIVE-INACTIVE-2371197c19ed805ab509f552817e823a)\n" + @@ -246,6 +253,7 @@ public BaseResponse updatePartnershipStatus( partnershipService.updatePartnershipStatus(partnershipId, request, pd.getId(), pd.getRole())); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_GET_DETAIL) @Operation( summary = "제휴 상세조회 API", description = "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2371197c19ed80cdac8beb2ffddb2f61)\n" + @@ -283,6 +291,7 @@ public BaseResponse getPartnership( partnershipService.getPartnership(partnershipId, pd.getId(), pd.getRole())); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_DELETE) @Operation( summary = "제휴 제안서 삭제 API", description = "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed80e58d30c469e4ba3146)\n" + @@ -300,6 +309,7 @@ public BaseResponse deletePartnership( return BaseResponse.onSuccess(SuccessStatus._OK, null); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_DELETE_SUSPENDED) @Operation( summary = "대기 중인 제휴 계약서 삭제 API", description = "- 관리자 관점에서 대기 중(SUSPEND) 상태인 제휴 계약서를 삭제합니다.\n" + @@ -411,6 +421,7 @@ public BaseResponse> suspendPartnership( return BaseResponse.onSuccess(SuccessStatus._OK, partnershipService.getSuspendedPapers(pd.getId())); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_CHECK_WITH_PARTNER) @Operation( summary = "채팅방 내 제휴 확인 API", description = "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/_-31f1197c19ed8017bceced3b3d65c0d7?source=copy_link)\n" + @@ -435,6 +446,7 @@ public BaseResponse checkAdminPartnership( return BaseResponse.onSuccess(SuccessStatus._OK, partnershipService.checkPartnershipWithPartner(pd.getId(), partnerId)); } + @ApiErrorCodeExamples(SwaggerErrorCodes.PARTNERSHIP_CHECK_WITH_ADMIN) @Operation( summary = "채팅방 내 제휴 확인 API(제휴업체용)", description = "# [v1.3 (2026-01-04)](https://clumsy-seeder-416.notion.site/2fe1197c19ed8078af77d65bfcc09087)\n" + diff --git a/src/main/java/com/assu/server/domain/qr/controller/TemporaryQrController.java b/src/main/java/com/assu/server/domain/qr/controller/TemporaryQrController.java index bf3de71b..a49cf1aa 100644 --- a/src/main/java/com/assu/server/domain/qr/controller/TemporaryQrController.java +++ b/src/main/java/com/assu/server/domain/qr/controller/TemporaryQrController.java @@ -17,6 +17,8 @@ import com.assu.server.domain.qr.service.TemporaryQrService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; @@ -34,6 +36,7 @@ public class TemporaryQrController { private final TemporaryQrService temporaryQrService; @PostMapping("/data") + @ApiErrorCodeExamples(SwaggerErrorCodes.TEMPORARY_QR_INSERT_DATA) @Operation( summary = "QR 데이터 삽입 API", description = @@ -53,6 +56,7 @@ public ResponseEntity> insertQrData(@RequestBody TemporaryQrR } @GetMapping("/mydata") + @ApiErrorCodeExamples(SwaggerErrorCodes.TEMPORARY_QR_GET_MY_DATA) @Operation( summary = "내 QR 적립 데이터 조회 API", description = diff --git a/src/main/java/com/assu/server/domain/report/controller/ReportController.java b/src/main/java/com/assu/server/domain/report/controller/ReportController.java index ea167c29..171a59ad 100644 --- a/src/main/java/com/assu/server/domain/report/controller/ReportController.java +++ b/src/main/java/com/assu/server/domain/report/controller/ReportController.java @@ -5,6 +5,8 @@ import com.assu.server.domain.report.service.ReportService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -36,6 +38,7 @@ public class ReportController { " - 건의글 신고: SUGGESTION_INAPPROPRIATE_CONTENT, SUGGESTION_FALSE_INFORMATION, SUGGESTION_SPAM\n\n" + "**Response:**\n" + "- 성공 시 201(CREATED)과 신고 ID 반환") + @ApiErrorCodeExamples(SwaggerErrorCodes.REPORT_CREATE_CONTENT) @PostMapping public BaseResponse reportContent( @AuthenticationPrincipal PrincipalDetails principalDetails, @@ -59,6 +62,7 @@ public BaseResponse reportContent( + "**Response:**\n" + "- 성공 시 201(CREATED)과 신고 ID 반환") + @ApiErrorCodeExamples(SwaggerErrorCodes.REPORT_CREATE_STUDENT) @PostMapping("/students") public BaseResponse reportStudent( @AuthenticationPrincipal PrincipalDetails principalDetails, diff --git a/src/main/java/com/assu/server/domain/review/controller/ReviewController.java b/src/main/java/com/assu/server/domain/review/controller/ReviewController.java index f21a9c71..7efc9858 100644 --- a/src/main/java/com/assu/server/domain/review/controller/ReviewController.java +++ b/src/main/java/com/assu/server/domain/review/controller/ReviewController.java @@ -5,6 +5,8 @@ import com.assu.server.domain.review.service.ReviewService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -30,6 +32,7 @@ public class ReviewController { private final ReviewService reviewService; + @ApiErrorCodeExamples(SwaggerErrorCodes.REVIEW_WRITE) @Operation( summary = "리뷰 작성 API", description = "# [v1.0 (2025-09-02)](https://www.notion.so/2241197c19ed8176ba4fcb49c0136f93)\n" + @@ -59,6 +62,7 @@ public BaseResponse> checkStudent return BaseResponse.onSuccess(SuccessStatus._OK, reviewService.checkStudentReview(pd.getId(), pageable)); } + @ApiErrorCodeExamples(SwaggerErrorCodes.REVIEW_CHECK_PARTNER) @Operation( summary = "내 가게 리뷰 조회 API", description = "# [v1.0 (2025-09-02)](https://www.notion.so/_-2241197c19ed8130b89ad5a77f3e8b2c)\n" + @@ -72,6 +76,7 @@ public BaseResponse> checkPartner return BaseResponse.onSuccess(SuccessStatus._OK, reviewService.checkPartnerReview(pd.getId(), pageable)); } + @ApiErrorCodeExamples(SwaggerErrorCodes.REVIEW_CHECK_STORE) @Operation( summary = "가게 리뷰 조회 API", description = "# [v1.0 (2025-09-02)](https://www.notion.so/2681197c19ed80038db3f7dd357623ff)\n" + @@ -84,6 +89,7 @@ public BaseResponse> checkStoreRe return BaseResponse.onSuccess(SuccessStatus._OK, reviewService.checkStoreReview(storeId, pageable)); } + @ApiErrorCodeExamples(SwaggerErrorCodes.REVIEW_DELETE) @Operation( summary = "내가 쓴 리뷰 삭제 API", description = "# [v1.0 (2025-09-02)](https://www.notion.so/2241197c19ed81a58e93c9ba56f6cb9a)\n" + @@ -108,6 +114,7 @@ public ResponseEntity> return ResponseEntity.ok(BaseResponse.onSuccess(SuccessStatus._OK, reviewService.standardScore(storeId))); } + @ApiErrorCodeExamples(SwaggerErrorCodes.REVIEW_MY_STORE_AVERAGE) @Operation( summary = "내 가게 리뷰 평균 조회 API (파트너)", description = "# [v1.0 (2025-09-02)](https://www.notion.so/API-2681197c19ed80df9f2ac100812c7f44)\n" + diff --git a/src/main/java/com/assu/server/domain/store/controller/StoreController.java b/src/main/java/com/assu/server/domain/store/controller/StoreController.java index 7a43e91f..64eb0562 100644 --- a/src/main/java/com/assu/server/domain/store/controller/StoreController.java +++ b/src/main/java/com/assu/server/domain/store/controller/StoreController.java @@ -14,6 +14,8 @@ import com.assu.server.domain.store.service.StoreService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; @@ -35,6 +37,7 @@ public class StoreController { private final PaperQueryService paperQueryService; @GetMapping("/{storeId}") + @ApiErrorCodeExamples(SwaggerErrorCodes.STORE_GET_DETAIL) @Operation( summary = "가게 상세 조회 API", description = "# [v1.0 (2026-08-31)](https://clumsy-seeder-416.notion.site/3cd1197c19ed806eb1abce6ab4c5f4fb?source=copy_link)\n" + @@ -83,6 +86,7 @@ public ResponseEntity> getTodayBestStore() { } @GetMapping("/{storeId}/papers") + @ApiErrorCodeExamples(SwaggerErrorCodes.STORE_GET_PAPER_CONTENT) @Operation( summary = "제휴 컨텐츠 조회 API", description = "# [v1.0 (2026-02-14)](https://clumsy-seeder-416.notion.site/2361197c19ed8019b8b8cb054cd3135b?source=copy_link)\n" + @@ -153,6 +157,7 @@ public ResponseEntity> getSta ) @GetMapping("/ranking") @PreAuthorize("hasRole('PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.STORE_GET_WEEKLY_RANK) public ResponseEntity> getWeeklyRank( @AuthenticationPrincipal PrincipalDetails pd) { return ResponseEntity.ok(BaseResponse.onSuccess(SuccessStatus._OK, storeService.getWeeklyRank(pd.getId()))); @@ -164,6 +169,7 @@ public ResponseEntity> getW ) @GetMapping("/ranking/weekly") @PreAuthorize("hasRole('PARTNER')") + @ApiErrorCodeExamples(SwaggerErrorCodes.STORE_GET_WEEKLY_RANK_LIST) public BaseResponse> getWeeklyRankByPartnerId( @AuthenticationPrincipal PrincipalDetails pd ){ diff --git a/src/main/java/com/assu/server/domain/student/controller/StudentController.java b/src/main/java/com/assu/server/domain/student/controller/StudentController.java index d0255d1d..d3af1154 100644 --- a/src/main/java/com/assu/server/domain/student/controller/StudentController.java +++ b/src/main/java/com/assu/server/domain/student/controller/StudentController.java @@ -22,6 +22,8 @@ import com.assu.server.domain.student.service.StudentService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; @@ -89,6 +91,7 @@ public ResponseEntity>> getUnr "\n**Response:**\n" + " - stamp 개수 반환 \n" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.STUDENT_GET_STAMP) @GetMapping("/stamp") public BaseResponse getStamp( @AuthenticationPrincipal PrincipalDetails pd @@ -101,6 +104,7 @@ public BaseResponse getStamp( description = "# [v1.0 (2026-02-23)](https://clumsy-seeder-416.notion.site/3101197c19ed80b5b47eceb202535469)\n" + "- 스탬프가 10개가 되는 시점에 자동으로 응모및 알림" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.STUDENT_EARN_STAMP) @PostMapping("/stamp") public BaseResponse earnStamp( @AuthenticationPrincipal PrincipalDetails pd @@ -159,6 +163,7 @@ public BaseResponse> getRecommendC "- 401(UNAUTHORIZED): 인증되지 않은 사용자\n" + "- 404(NOT_FOUND): 사용자 정보를 찾을 수 없음" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.STUDENT_GET_PROFILE) @GetMapping("/info") public BaseResponse getStudentProfile( @AuthenticationPrincipal PrincipalDetails pd @@ -175,6 +180,7 @@ public BaseResponse getStudentProfile( "- 401(UNAUTHORIZED): 인증되지 않은 사용자\n" + "- 404(NOT_FOUND): 학생 정보를 찾을 수 없음" ) + @ApiErrorCodeExamples(SwaggerErrorCodes.STUDENT_GET_HOME_CURATION) @GetMapping("/recommend/curation") public BaseResponse getRecommendCuration( @AuthenticationPrincipal PrincipalDetails pd diff --git a/src/main/java/com/assu/server/domain/suggestion/controller/SuggestionController.java b/src/main/java/com/assu/server/domain/suggestion/controller/SuggestionController.java index d5546f26..7694e52e 100644 --- a/src/main/java/com/assu/server/domain/suggestion/controller/SuggestionController.java +++ b/src/main/java/com/assu/server/domain/suggestion/controller/SuggestionController.java @@ -7,6 +7,8 @@ import com.assu.server.domain.suggestion.service.SuggestionService; import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -42,6 +44,7 @@ public class SuggestionController { " - `adminId` (Long): 건의 대상 관리자 ID\n" + " - `storeName` (String): 희망 가게 이름\n" + " - `suggestionBenefit` (String): 희망 혜택\n") + @ApiErrorCodeExamples(SwaggerErrorCodes.SUGGESTION_WRITE) @PostMapping @PreAuthorize("hasRole('STUDENT')") public BaseResponse writeSuggestion( @@ -63,6 +66,7 @@ public BaseResponse writeSuggestion( " - `departName` (String): 단과대학 학생회 이름\n" + " - `majorId` (Long): 학부/학과 학생회 ID\n" + " - `majorName` (String): 학부/학과 학생회 이름\n") + @ApiErrorCodeExamples(SwaggerErrorCodes.SUGGESTION_GET_ADMINS) @GetMapping("/admin") @PreAuthorize("hasRole('STUDENT')") public BaseResponse getSuggestionAdmins( diff --git a/src/main/java/com/assu/server/global/apiPayload/code/status/SwaggerErrorCodes.java b/src/main/java/com/assu/server/global/apiPayload/code/status/SwaggerErrorCodes.java new file mode 100644 index 00000000..ca0854b9 --- /dev/null +++ b/src/main/java/com/assu/server/global/apiPayload/code/status/SwaggerErrorCodes.java @@ -0,0 +1,494 @@ +package com.assu.server.global.apiPayload.code.status; + +import lombok.Getter; + +import java.util.Set; + +@Getter +public enum SwaggerErrorCodes { + + // ===== Admin / Auth ===== + ADMIN_PARTNER_RECOMMEND(Set.of( + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.NO_AVAILABLE_PARTNER + )), + ADMIN_DASHBOARD_COUNT_ADMIN(Set.of( + ErrorStatus.NO_SUCH_ADMIN + )), + ADMIN_DASHBOARD_NEW_STUDENT_COUNT(Set.of( + ErrorStatus.NO_SUCH_ADMIN + )), + ADMIN_DASHBOARD_COUNT_USER(Set.of( + ErrorStatus.NO_SUCH_ADMIN + )), + ADMIN_DASHBOARD_TOP_USAGE(Set.of( + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.NO_USAGE_DATA, + ErrorStatus.NO_PAPER_FOR_STORE + )), + ADMIN_DASHBOARD_USAGE_LIST(Set.of( + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.NO_PAPER_FOR_STORE + )), + AUTH_PHONE_SEND_CODE(Set.of( + ErrorStatus.EXISTED_PHONE, + ErrorStatus.FAILED_TO_SEND_SMS, + ErrorStatus.FAILED_TO_PARSE_ALIGO + )), + AUTH_PHONE_VERIFY_CODE(Set.of( + ErrorStatus.NOT_VERIFIED_PHONE_NUMBER + )), + AUTH_EMAIL_CHECK(Set.of( + ErrorStatus.EXISTED_EMAIL + )), + AUTH_SIGNUP_STUDENT(Set.of( + ErrorStatus.SSU_SAINT_SSO_FAILED, + ErrorStatus.SSU_SAINT_PORTAL_FAILED, + ErrorStatus.SSU_SAINT_PARSE_FAILED, + ErrorStatus.SSU_SAINT_UNSUPPORTED_MAJOR, + ErrorStatus.EXISTED_STUDENT, + ErrorStatus.AUTHORIZATION_EXCEPTION + )), + AUTH_SIGNUP_PARTNER(Set.of( + ErrorStatus.NOT_VERIFIED_PHONE_NUMBER, + ErrorStatus.EXISTED_PHONE, + ErrorStatus._BAD_REQUEST, + ErrorStatus.EXISTED_EMAIL, + ErrorStatus.AUTHORIZATION_EXCEPTION + )), + AUTH_SIGNUP_ADMIN(Set.of( + ErrorStatus.NOT_VERIFIED_PHONE_NUMBER, + ErrorStatus.EXISTED_PHONE, + ErrorStatus.EXISTED_EMAIL, + ErrorStatus._BAD_REQUEST, + ErrorStatus.AUTHORIZATION_EXCEPTION + )), + AUTH_LOGIN_COMMON(Set.of( + ErrorStatus.MEMBER_PENDING_APPROVAL, + ErrorStatus.BACKOFFICE_USE_DEDICATED_LOGIN, + ErrorStatus.AUTHORIZATION_EXCEPTION + )), + AUTH_LOGIN_STUDENT(Set.of( + ErrorStatus.SSU_SAINT_SSO_FAILED, + ErrorStatus.SSU_SAINT_PORTAL_FAILED, + ErrorStatus.SSU_SAINT_PARSE_FAILED, + ErrorStatus.SSU_SAINT_UNSUPPORTED_MAJOR, + ErrorStatus.AUTHORIZATION_EXCEPTION, + ErrorStatus.NO_SUCH_MEMBER + )), + AUTH_TOKEN_REFRESH(Set.of( + ErrorStatus.BACKOFFICE_USE_DEDICATED_LOGIN, + ErrorStatus.JWT_REFRESH_TOKEN_EXPIRED, + ErrorStatus.AUTHORIZATION_EXCEPTION, + ErrorStatus.REFRESH_TOKEN_NOT_EQUAL + )), + AUTH_LOGOUT(Set.of( + ErrorStatus.AUTHORIZATION_EXCEPTION + )), + AUTH_SSU_VERIFY(Set.of( + ErrorStatus.SSU_SAINT_SSO_FAILED, + ErrorStatus.SSU_SAINT_PORTAL_FAILED, + ErrorStatus.SSU_SAINT_PARSE_FAILED, + ErrorStatus.SSU_SAINT_UNSUPPORTED_MAJOR + )), + AUTH_WITHDRAW(Set.of( + ErrorStatus.AUTHORIZATION_EXCEPTION, + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.MEMBER_ALREADY_WITHDRAWN + )), + BACKOFFICE_AUTH_LOGIN(Set.of( + ErrorStatus.NO_BACKOFFICE_TYPE, + ErrorStatus.AUTHORIZATION_EXCEPTION + )), + BACKOFFICE_AUTH_REFRESH(Set.of( + ErrorStatus.JWT_AUDIENCE_MISMATCH, + ErrorStatus.JWT_REFRESH_TOKEN_EXPIRED, + ErrorStatus.AUTHORIZATION_EXCEPTION, + ErrorStatus.REFRESH_TOKEN_NOT_EQUAL + )), + + // ===== Backoffice: Admin/Member/Partner/Operator ===== + BACKOFFICE_ADMIN_GET_SIGN_IMAGE(Set.of( + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.SIGN_IMAGE_NOT_FOUND + )), + BACKOFFICE_ADMIN_CREATE(Set.of( + ErrorStatus.EXISTED_EMAIL, + ErrorStatus.EXISTED_PHONE + )), + BACKOFFICE_ADMIN_UPDATE(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.EXISTED_EMAIL, + ErrorStatus.EXISTED_PHONE + )), + BACKOFFICE_ADMIN_DELETE(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + BACKOFFICE_MEMBER_GET_DETAIL(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + BACKOFFICE_MEMBER_APPROVE(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.MEMBER_APPROVAL_NOT_SUPPORTED, + ErrorStatus.MEMBER_ALREADY_WITHDRAWN, + ErrorStatus.MEMBER_NOT_PENDING_APPROVAL, + ErrorStatus.PARTNER_STORE_NOT_FOUND + )), + BACKOFFICE_MEMBER_REJECT(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.MEMBER_APPROVAL_NOT_SUPPORTED, + ErrorStatus.MEMBER_ALREADY_WITHDRAWN, + ErrorStatus.MEMBER_NOT_PENDING_APPROVAL + )), + BACKOFFICE_MEMBER_FORCE_WITHDRAW(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.CANNOT_WITHDRAW_BACKOFFICE_MEMBER, + ErrorStatus.MEMBER_ALREADY_WITHDRAWN + )), + BACKOFFICE_MEMBER_RESTORE(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.MEMBER_NOT_DELETED + )), + BACKOFFICE_PARTNER_GET_LICENSE(Set.of( + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.LICENSE_NOT_FOUND + )), + BACKOFFICE_PARTNER_VERIFY_LICENSE(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.LICENSE_NOT_FOUND + )), + BACKOFFICE_PARTNER_UPDATE_PROFILE_IMAGE(Set.of( + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.PROFILE_IMAGE_NOT_FOUND, + ErrorStatus.FILE_SIZE_EXCEEDED, + ErrorStatus.INVALID_FILE_NAME, + ErrorStatus.INVALID_FILE_TYPE, + ErrorStatus.INVALID_CONTENT_TYPE + )), + BACKOFFICE_PARTNER_DELETE_PROFILE_IMAGE(Set.of( + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.PROFILE_IMAGE_NOT_FOUND, + ErrorStatus.PROFILE_IMAGE_DELETE_FAILED + )), + BACKOFFICE_PARTNER_BATCH_SIGNUP(Set.of( + ErrorStatus.EXISTED_EMAIL + )), + BACKOFFICE_OPERATOR_CREATE(Set.of( + ErrorStatus.EXISTED_EMAIL + )), + + // ===== Backoffice: Paper/Partnership/HomeCuration/Chat/Inquiry/Notification/Report/DevSync ===== + BACKOFFICE_PAPER_CREATE(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + BACKOFFICE_PAPER_CONTENT_ADD(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + BACKOFFICE_PAPER_APPROVE(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.ALREADY_APPROVED + )), + BACKOFFICE_PAPER_REJECT(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + BACKOFFICE_PAPER_EXPIRE(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + BACKOFFICE_HOME_CURATION_UPDATE(Set.of( + ErrorStatus._BAD_REQUEST, + ErrorStatus.NO_SUCH_STORE + )), + BACKOFFICE_CHAT_BLOCK_BETWEEN(Set.of( + ErrorStatus._BAD_REQUEST, + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.ALREADY_CHAT_BLOCKED + )), + BACKOFFICE_CHAT_UNBLOCK_BETWEEN(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.NOT_CHAT_BLOCKED + )), + BACKOFFICE_CHAT_BLOCK_MEMBER(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.ALREADY_CHAT_BLOCKED + )), + BACKOFFICE_CHAT_UNBLOCK_MEMBER(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.NOT_CHAT_BLOCKED + )), + BACKOFFICE_INQUIRY_LIST(Set.of( + ErrorStatus.PAGE_UNDER_ONE, + ErrorStatus.PAGE_SIZE_INVALID + )), + BACKOFFICE_INQUIRY_DETAIL(Set.of( + ErrorStatus.NO_SUCH_INQUIRY + )), + BACKOFFICE_INQUIRY_ANSWER(Set.of( + ErrorStatus.NO_SUCH_INQUIRY, + ErrorStatus.ALREADY_ANSWERED + )), + BACKOFFICE_NOTIFICATION_PUSH_SEND(Set.of( + ErrorStatus.RECEIVER_ID_REQUIRED, + ErrorStatus.NO_SUCH_MEMBER + )), + BACKOFFICE_NOTIFICATION_PUSH_LOG_LIST(Set.of( + ErrorStatus.PAGE_UNDER_ONE, + ErrorStatus.PAGE_SIZE_INVALID + )), + BACKOFFICE_NOTIFICATION_OUTBOX_FAILED_LIST(Set.of( + ErrorStatus.PAGE_UNDER_ONE, + ErrorStatus.PAGE_SIZE_INVALID + )), + BACKOFFICE_NOTIFICATION_OUTBOX_RETRY(Set.of( + ErrorStatus.OUTBOX_NOT_FOUND, + ErrorStatus.OUTBOX_NOT_FAILED + )), + BACKOFFICE_REPORT_DETAIL(Set.of( + ErrorStatus.NO_SUCH_REPORT + )), + BACKOFFICE_REPORT_STATUS_UPDATE(Set.of( + ErrorStatus.NO_SUCH_REPORT, + ErrorStatus._BAD_REQUEST + )), + BACKOFFICE_REPORT_REJECT(Set.of( + ErrorStatus._BAD_REQUEST + )), + BACKOFFICE_REVIEW_DELETE(Set.of( + ErrorStatus._BAD_REQUEST + )), + BACKOFFICE_SUGGESTION_DELETE(Set.of( + ErrorStatus.NO_SUCH_SUGGESTION, + ErrorStatus._BAD_REQUEST + )), + BACKOFFICE_DEV_SYNC(Set.of( + ErrorStatus.INVALID_DEV_SYNC_TARGET, + ErrorStatus._INTERNAL_SERVER_ERROR + )), + + // ===== Certification / Chat / DeviceToken / Member / Notification ===== + CERTIFICATION_EXPIRE_SESSION(Set.of( + ErrorStatus.NO_SUCH_SESSION, + ErrorStatus._FORBIDDEN + )), + CERTIFICATION_PERSONAL(Set.of( + ErrorStatus.NO_SUCH_STORE + )), + CHAT_CREATE_ROOM(Set.of( + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.NO_SUCH_STORE, + ErrorStatus.NO_SUCH_STORE_WITH_THAT_PARTNER + )), + CHAT_GET_HISTORY(Set.of( + ErrorStatus.NO_SUCH_ROOM + )), + CHAT_LEAVE_ROOM(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.NO_MEMBER_IN_THE_ROOM, + ErrorStatus.NO_MEMBER + )), + CHAT_BLOCK_MEMBER(Set.of( + ErrorStatus._BAD_REQUEST + )), + CHAT_CHECK_BLOCK(Set.of( + ErrorStatus._BAD_REQUEST + )), + CHAT_UNBLOCK_MEMBER(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + CHAT_GET_BLOCK_LIST(Set.of( + ErrorStatus._BAD_REQUEST + )), + DEVICE_TOKEN_REGISTER(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + DEVICE_TOKEN_UNREGISTER(Set.of( + ErrorStatus.DEVICE_TOKEN_NOT_OWNED, + ErrorStatus.DEVICE_TOKEN_NOT_FOUND + )), + MEMBER_UPLOAD_PROFILE_IMAGE(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.PROFILE_IMAGE_NOT_FOUND, + ErrorStatus.FILE_SIZE_EXCEEDED, + ErrorStatus.INVALID_FILE_NAME, + ErrorStatus.INVALID_FILE_TYPE, + ErrorStatus.INVALID_CONTENT_TYPE + )), + MEMBER_GET_PROFILE_IMAGE(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.PROFILE_IMAGE_NOT_FOUND + )), + MEMBER_DELETE_PROFILE_IMAGE(Set.of( + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.PROFILE_IMAGE_NOT_FOUND, + ErrorStatus.PROFILE_IMAGE_DELETE_FAILED + )), + NOTIFICATION_LIST(Set.of( + ErrorStatus.PAGE_UNDER_ONE, + ErrorStatus.PAGE_SIZE_INVALID, + ErrorStatus.NO_SUCH_MEMBER + )), + NOTIFICATION_MARK_READ(Set.of( + ErrorStatus.NOTIFICATION_NOT_FOUND, + ErrorStatus.NOTIFICATION_ACCESS_DENIED + )), + NOTIFICATION_QUEUE(Set.of( + ErrorStatus.INVALID_NOTIFICATION_TYPE, + ErrorStatus.MISSING_NOTIFICATION_FIELD, + ErrorStatus.NO_SUCH_MEMBER + )), + NOTIFICATION_TOGGLE(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + NOTIFICATION_GET_SETTINGS(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + + // ===== Partner / QR / Report / Suggestion / Inquiry ===== + PARTNER_RANDOM_ADMIN_RECOMMEND(Set.of( + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.NO_SUCH_ADMIN + )), + TEMPORARY_QR_INSERT_DATA(Set.of( + ErrorStatus.NO_SUCH_STUDENT + )), + TEMPORARY_QR_GET_MY_DATA(Set.of( + ErrorStatus.NO_SUCH_STUDENT + )), + REPORT_CREATE_CONTENT(Set.of( + ErrorStatus.NO_MEMBER, + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.REVIEW_REPORT_SELF_NOT_ALLOWED, + ErrorStatus.NO_SUCH_SUGGESTION, + ErrorStatus.SUGGESTION_REPORT_SELF_NOT_ALLOWED, + ErrorStatus.INVALID_REPORT_TYPE, + ErrorStatus.REPORT_DUPLICATE + )), + REPORT_CREATE_STUDENT(Set.of( + ErrorStatus.NO_MEMBER, + ErrorStatus.NO_SUCH_MEMBER, + ErrorStatus.NO_SUCH_SUGGESTION, + ErrorStatus.INVALID_REPORT_TYPE, + ErrorStatus.REPORT_SELF_NOT_ALLOWED, + ErrorStatus.REPORT_DUPLICATE + )), + SUGGESTION_WRITE(Set.of( + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.NO_SUCH_STUDENT + )), + SUGGESTION_GET_ADMINS(Set.of( + ErrorStatus.NO_SUCH_STUDENT + )), + INQUIRY_CREATE(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )), + INQUIRY_LIST(Set.of( + ErrorStatus.PAGE_UNDER_ONE, + ErrorStatus.PAGE_SIZE_INVALID + )), + INQUIRY_GET(Set.of( + ErrorStatus.NO_SUCH_INQUIRY, + ErrorStatus.FORBIDDEN_INQUIRY + )), + + // ===== Partnership / Review / Student / Store / AppReview ===== + PARTNERSHIP_RECORD_USAGE(Set.of( + ErrorStatus.NO_SUCH_CONTENT, + ErrorStatus.NO_SUCH_STORE + )), + PARTNERSHIP_CREATE_DRAFT(Set.of( + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.NO_SUCH_STORE + )), + PARTNERSHIP_CREATE_MANUAL(Set.of( + ErrorStatus._BAD_REQUEST, + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.IMAGE_UPLOAD_FAILED + )), + PARTNERSHIP_UPDATE(Set.of( + ErrorStatus._BAD_REQUEST, + ErrorStatus.NO_SUCH_PAPER + )), + PARTNERSHIP_UPDATE_STATUS(Set.of( + ErrorStatus.NO_SUCH_PAPER, + ErrorStatus._FORBIDDEN, + ErrorStatus._BAD_REQUEST, + ErrorStatus.NO_SUCH_ADMIN, + ErrorStatus.NO_SUCH_PARTNER + )), + PARTNERSHIP_GET_DETAIL(Set.of( + ErrorStatus.NO_SUCH_PAPER, + ErrorStatus._FORBIDDEN + )), + PARTNERSHIP_DELETE(Set.of( + ErrorStatus.NO_SUCH_PAPER, + ErrorStatus._FORBIDDEN + )), + PARTNERSHIP_DELETE_SUSPENDED(Set.of( + ErrorStatus.NO_SUCH_PAPER, + ErrorStatus._FORBIDDEN, + ErrorStatus._BAD_REQUEST + )), + PARTNERSHIP_CHECK_WITH_PARTNER(Set.of( + ErrorStatus.NO_SUCH_PARTNER + )), + PARTNERSHIP_CHECK_WITH_ADMIN(Set.of( + ErrorStatus.NO_SUCH_ADMIN + )), + REVIEW_WRITE(Set.of( + ErrorStatus.NO_SUCH_STORE, + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.NO_SUCH_STUDENT, + ErrorStatus.IMAGE_UPLOAD_FAILED, + ErrorStatus.NO_SUCH_USAGE + )), + REVIEW_CHECK_PARTNER(Set.of( + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.NO_SUCH_STORE + )), + REVIEW_CHECK_STORE(Set.of( + ErrorStatus.NO_SUCH_STORE + )), + REVIEW_DELETE(Set.of( + ErrorStatus._BAD_REQUEST + )), + REVIEW_MY_STORE_AVERAGE(Set.of( + ErrorStatus.NO_SUCH_PARTNER, + ErrorStatus.NO_SUCH_STORE + )), + STUDENT_GET_STAMP(Set.of( + ErrorStatus.NO_SUCH_STUDENT + )), + STUDENT_EARN_STAMP(Set.of( + ErrorStatus.NO_SUCH_STUDENT + )), + STUDENT_GET_PROFILE(Set.of( + ErrorStatus.NO_SUCH_STUDENT + )), + STUDENT_GET_HOME_CURATION(Set.of( + ErrorStatus.NO_SUCH_STUDENT + )), + STORE_GET_DETAIL(Set.of( + ErrorStatus.NO_SUCH_STORE + )), + STORE_GET_PAPER_CONTENT(Set.of( + ErrorStatus.NO_STUDENT_TYPE, + ErrorStatus.NO_SUCH_STORE + )), + STORE_GET_WEEKLY_RANK(Set.of( + ErrorStatus.NO_SUCH_STORE + )), + STORE_GET_WEEKLY_RANK_LIST(Set.of( + ErrorStatus.NO_SUCH_STORE + )), + APP_REVIEW_CREATE(Set.of( + ErrorStatus.NO_SUCH_MEMBER + )); + + private final Set errorCodes; + + SwaggerErrorCodes(Set errorCodes) { + this.errorCodes = errorCodes; + } +} diff --git a/src/main/java/com/assu/server/global/config/SwaggerConfig.java b/src/main/java/com/assu/server/global/config/SwaggerConfig.java index 4191e914..251094fd 100644 --- a/src/main/java/com/assu/server/global/config/SwaggerConfig.java +++ b/src/main/java/com/assu/server/global/config/SwaggerConfig.java @@ -1,13 +1,29 @@ package com.assu.server.global.config; +import com.assu.server.global.apiPayload.code.status.ErrorStatus; +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; +import com.assu.server.global.exception.annotation.ApiErrorCodeExamples; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.examples.Example; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.servers.Server; +import org.springdoc.core.customizers.OperationCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.HandlerMethod; + +import java.util.List; +import java.util.Map; + +import static java.util.stream.Collectors.groupingBy; @Configuration public class SwaggerConfig { @@ -34,4 +50,48 @@ public OpenAPI stewAPI() { .addSecurityItem(securityRequirement) .components(components); } + + @Bean + public OperationCustomizer customExceptionOperationCustomizer() { + return (Operation operation, HandlerMethod handlerMethod) -> { + ApiErrorCodeExamples description = handlerMethod.getMethodAnnotation(ApiErrorCodeExamples.class); + if (description != null) { + addErrorResponseExamples(operation, description.value()); + } + return operation; + }; + } + + private void addErrorResponseExamples(Operation operation, SwaggerErrorCodes swaggerErrorCodes) { + ApiResponses responses = operation.getResponses(); + + Map> byHttpStatus = swaggerErrorCodes.getErrorCodes().stream() + .map(errorStatus -> new ExampleHolder( + toExample(errorStatus), + errorStatus.name(), + errorStatus.getHttpStatus().value())) + .collect(groupingBy(ExampleHolder::httpStatus)); + + byHttpStatus.forEach((httpStatus, holders) -> { + MediaType mediaType = new MediaType(); + holders.forEach(holder -> mediaType.addExamples(holder.name(), holder.example())); + + Content content = new Content().addMediaType("application/json", mediaType); + responses.addApiResponse(String.valueOf(httpStatus), new ApiResponse().description("").content(content)); + }); + } + + private Example toExample(ErrorStatus errorStatus) { + Example example = new Example(); + example.description(errorStatus.getMessage()); + example.setValue(Map.of( + "isSuccess", false, + "code", errorStatus.getCode(), + "message", errorStatus.getMessage() + )); + return example; + } + + private record ExampleHolder(Example example, String name, int httpStatus) { + } } diff --git a/src/main/java/com/assu/server/global/exception/annotation/ApiErrorCodeExamples.java b/src/main/java/com/assu/server/global/exception/annotation/ApiErrorCodeExamples.java new file mode 100644 index 00000000..317bbd18 --- /dev/null +++ b/src/main/java/com/assu/server/global/exception/annotation/ApiErrorCodeExamples.java @@ -0,0 +1,14 @@ +package com.assu.server.global.exception.annotation; + +import com.assu.server.global.apiPayload.code.status.SwaggerErrorCodes; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApiErrorCodeExamples { + SwaggerErrorCodes value(); +}