diff --git a/docs/api-specs/notification-api.md b/docs/api-specs/notification-api.md index 6b6dac0..e111310 100644 --- a/docs/api-specs/notification-api.md +++ b/docs/api-specs/notification-api.md @@ -345,6 +345,7 @@ | Method | Path | 설명 | |---|---|---| | `POST` | `/api/v1/admin/notices` | 공지사항/이벤트 작성 (즉시 전체 발송) | +| `GET` | `/api/v1/admin/notices/options` | 공지 작성 시 선택 가능한 `category` 목록 조회 | | `GET` | `/api/v1/admin/notices/target-count` | 지금 등록하면 몇 대의 디바이스에 발송되는지 미리 조회 | | `GET` | `/api/v1/admin/notices` | 공지 목록 조회 (`category`, `page`, `size` 쿼리) | | `GET` | `/api/v1/admin/notices/{noticeId}` | 공지 상세 조회 | @@ -371,6 +372,22 @@ 응답은 `AdminNoticeDetailResponse` (`notificationId`, `category`, `detailCode`, `title`, `body`, `referenceId`, `createdAt`). +**`GET /api/v1/admin/notices/options`** + +공지 작성 폼의 카테고리 선택지를 서버 enum 기준으로 내려줍니다. `ALL`은 목록 조회 필터용이라 작성 옵션에는 포함되지 않습니다. + +성공 응답 `200 OK`: + +```json +{ + "statusCode": 200, + "data": { + "categories": ["CONTENT", "NOTICE", "EVENT"] + }, + "error": null +} +``` + **`GET /api/v1/admin/notices/target-count`** `NOTICE`/`EVENT` 공지를 지금 등록하면 몇 대의 디바이스에 발송되는지 미리 조회합니다. `notifyAdminNotice`가 사용하는 것과 동일하게 '이벤트 및 소식 알림' 설정이 ON인 유저의 등록된 디바이스 수 기준입니다. `CONTENT` 카테고리 공지는 애초에 이 대상자 산정을 타지 않으므로 참고용으로만 사용하세요. diff --git a/src/main/java/com/swyp/picke/domain/admin/controller/AdminNotificationController.java b/src/main/java/com/swyp/picke/domain/admin/controller/AdminNotificationController.java index be0f213..b4d3b6b 100644 --- a/src/main/java/com/swyp/picke/domain/admin/controller/AdminNotificationController.java +++ b/src/main/java/com/swyp/picke/domain/admin/controller/AdminNotificationController.java @@ -6,6 +6,7 @@ import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeDeliveryResultResponse; import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeDetailResponse; import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeListResponse; +import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeOptionsResponse; import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeTargetCountResponse; import com.swyp.picke.domain.admin.service.AdminNotificationService; import com.swyp.picke.domain.notification.enums.NotificationCategory; @@ -44,6 +45,12 @@ public ApiResponse createNotice( return ApiResponse.onSuccess(adminNotificationService.createNotice(request)); } + @Operation(summary = "공지사항 작성 옵션 조회", description = "공지 작성 시 선택 가능한 category 목록을 내려준다.") + @GetMapping("/options") + public ApiResponse getOptions() { + return ApiResponse.onSuccess(adminNotificationService.getOptions()); + } + @Operation(summary = "공지사항 목록 조회") @GetMapping public ApiResponse getNotices( diff --git a/src/main/java/com/swyp/picke/domain/admin/dto/notification/response/AdminNoticeOptionsResponse.java b/src/main/java/com/swyp/picke/domain/admin/dto/notification/response/AdminNoticeOptionsResponse.java new file mode 100644 index 0000000..ae906dc --- /dev/null +++ b/src/main/java/com/swyp/picke/domain/admin/dto/notification/response/AdminNoticeOptionsResponse.java @@ -0,0 +1,7 @@ +package com.swyp.picke.domain.admin.dto.notification.response; + +import java.util.List; + +public record AdminNoticeOptionsResponse( + List categories +) {} diff --git a/src/main/java/com/swyp/picke/domain/admin/service/AdminNotificationService.java b/src/main/java/com/swyp/picke/domain/admin/service/AdminNotificationService.java index 55445fc..d46663c 100644 --- a/src/main/java/com/swyp/picke/domain/admin/service/AdminNotificationService.java +++ b/src/main/java/com/swyp/picke/domain/admin/service/AdminNotificationService.java @@ -5,6 +5,7 @@ import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeDeliveryResultResponse; import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeDetailResponse; import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeListResponse; +import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeOptionsResponse; import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeSummaryResponse; import com.swyp.picke.domain.admin.dto.notification.response.AdminNoticeTargetCountResponse; import com.swyp.picke.domain.notification.entity.Notification; @@ -17,6 +18,7 @@ import com.swyp.picke.domain.notification.service.NotificationService; import com.swyp.picke.global.common.exception.CustomException; import com.swyp.picke.global.common.exception.ErrorCode; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Slice; @@ -112,6 +114,15 @@ public AdminNoticeTargetCountResponse getTargetCount() { return new AdminNoticeTargetCountResponse(notificationDispatchService.countAdminNoticeTargets()); } + public AdminNoticeOptionsResponse getOptions() { + List categories = List.of( + NotificationCategory.CONTENT.name(), + NotificationCategory.NOTICE.name(), + NotificationCategory.EVENT.name() + ); + return new AdminNoticeOptionsResponse(categories); + } + private NotificationCategory normalizeCategory(NotificationCategory category) { if (category == null || category == NotificationCategory.ALL) { return null; diff --git a/src/test/java/com/swyp/picke/domain/admin/service/AdminNotificationServiceTest.java b/src/test/java/com/swyp/picke/domain/admin/service/AdminNotificationServiceTest.java index 621b5da..ad78960 100644 --- a/src/test/java/com/swyp/picke/domain/admin/service/AdminNotificationServiceTest.java +++ b/src/test/java/com/swyp/picke/domain/admin/service/AdminNotificationServiceTest.java @@ -144,4 +144,12 @@ void getTargetCount_returnsCount() { assertThat(response.targetCount()).isEqualTo(1200); } + + @Test + @DisplayName("공지 작성 시 선택 가능한 카테고리 목록을 조회한다") + void getOptions_returnsCreatableCategories() { + var response = adminNotificationService.getOptions(); + + assertThat(response.categories()).containsExactly("CONTENT", "NOTICE", "EVENT"); + } }