From 6bb32ce5ad3087c53816a62178faa06bb8d9248a Mon Sep 17 00:00:00 2001 From: rootTiket Date: Thu, 11 Sep 2025 23:26:10 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20Test=20API=20DTO=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PushTestRequest: FCM 푸시 테스트용 요청 DTO - CategoriesTestResponse: 카테고리 생성 테스트용 응답 DTO --- .../application/test/dto/request/PushTestRequest.java | 7 +++++++ .../test/dto/response/CategoriesTestResponse.java | 11 +++++++++++ 2 files changed, 18 insertions(+) create mode 100644 application/src/main/java/com/pinback/application/test/dto/request/PushTestRequest.java create mode 100644 application/src/main/java/com/pinback/application/test/dto/response/CategoriesTestResponse.java diff --git a/application/src/main/java/com/pinback/application/test/dto/request/PushTestRequest.java b/application/src/main/java/com/pinback/application/test/dto/request/PushTestRequest.java new file mode 100644 index 0000000..df1eda2 --- /dev/null +++ b/application/src/main/java/com/pinback/application/test/dto/request/PushTestRequest.java @@ -0,0 +1,7 @@ +package com.pinback.application.test.dto.request; + +public record PushTestRequest( + String fcmToken, + String message +) { +} diff --git a/application/src/main/java/com/pinback/application/test/dto/response/CategoriesTestResponse.java b/application/src/main/java/com/pinback/application/test/dto/response/CategoriesTestResponse.java new file mode 100644 index 0000000..57aed40 --- /dev/null +++ b/application/src/main/java/com/pinback/application/test/dto/response/CategoriesTestResponse.java @@ -0,0 +1,11 @@ +package com.pinback.application.test.dto.response; + +import java.util.List; + +public record CategoriesTestResponse( + List categories +) { + public static CategoriesTestResponse of(List categories) { + return new CategoriesTestResponse(categories); + } +} From 51e673231a39a6c9ab8a429e9513080b10d18a0c Mon Sep 17 00:00:00 2001 From: rootTiket Date: Thu, 11 Sep 2025 23:26:23 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20Test=20API=20=ED=8F=AC=ED=8A=B8=20?= =?UTF-8?q?=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TestPort: Test API 비즈니스 로직 인터페이스 - FcmServicePort: FCM 서비스 추상화 포트 --- .../application/test/port/in/TestPort.java | 15 +++++++++++++++ .../application/test/port/out/FcmServicePort.java | 5 +++++ 2 files changed, 20 insertions(+) create mode 100644 application/src/main/java/com/pinback/application/test/port/in/TestPort.java create mode 100644 application/src/main/java/com/pinback/application/test/port/out/FcmServicePort.java diff --git a/application/src/main/java/com/pinback/application/test/port/in/TestPort.java b/application/src/main/java/com/pinback/application/test/port/in/TestPort.java new file mode 100644 index 0000000..ccad30a --- /dev/null +++ b/application/src/main/java/com/pinback/application/test/port/in/TestPort.java @@ -0,0 +1,15 @@ +package com.pinback.application.test.port.in; + +import com.pinback.application.test.dto.request.PushTestRequest; +import com.pinback.application.test.dto.response.CategoriesTestResponse; +import com.pinback.domain.user.entity.User; + +public interface TestPort { + void pushTest(PushTestRequest request); + + void createArticlesByCategory(User user, Long categoryId); + + CategoriesTestResponse createCategories(User user); + + void deleteArticlesByCategory(User user, Long categoryId); +} diff --git a/application/src/main/java/com/pinback/application/test/port/out/FcmServicePort.java b/application/src/main/java/com/pinback/application/test/port/out/FcmServicePort.java new file mode 100644 index 0000000..767bec5 --- /dev/null +++ b/application/src/main/java/com/pinback/application/test/port/out/FcmServicePort.java @@ -0,0 +1,5 @@ +package com.pinback.application.test.port.out; + +public interface FcmServicePort { + void sendNotification(String token, String message); +} From 4ba9de030cd8665eb3c379e1809e430a8b0702ec Mon Sep 17 00:00:00 2001 From: rootTiket Date: Thu, 11 Sep 2025 23:26:37 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20Test=20API=20=EC=9C=A0=EC=8A=A4?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FCM 푸시 알림 테스트 - 카테고리별 아티클 5개 생성 - 디폴트 카테고리 10개 생성 (사용하지 않는 색상 자동 할당) - 카테고리별 아티클 삭제 --- .../application/test/usecase/TestUsecase.java | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 application/src/main/java/com/pinback/application/test/usecase/TestUsecase.java diff --git a/application/src/main/java/com/pinback/application/test/usecase/TestUsecase.java b/application/src/main/java/com/pinback/application/test/usecase/TestUsecase.java new file mode 100644 index 0000000..fcd8793 --- /dev/null +++ b/application/src/main/java/com/pinback/application/test/usecase/TestUsecase.java @@ -0,0 +1,112 @@ +package com.pinback.application.test.usecase; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.springframework.stereotype.Service; + +import com.pinback.application.article.port.out.ArticleDeleteServicePort; +import com.pinback.application.article.port.out.ArticleSaveServicePort; +import com.pinback.application.category.port.out.CategoryColorServicePort; +import com.pinback.application.category.port.out.CategoryGetServicePort; +import com.pinback.application.category.port.out.CategorySaveServicePort; +import com.pinback.application.test.dto.request.PushTestRequest; +import com.pinback.application.test.dto.response.CategoriesTestResponse; +import com.pinback.application.test.port.in.TestPort; +import com.pinback.application.test.port.out.FcmServicePort; +import com.pinback.application.user.port.out.UserGetServicePort; +import com.pinback.domain.article.entity.Article; +import com.pinback.domain.category.entity.Category; +import com.pinback.domain.category.enums.CategoryColor; +import com.pinback.domain.user.entity.User; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class TestUsecase implements TestPort { + private static final int CATEGORY_LIMIT = 10; + private final FcmServicePort fcmService; + private final CategoryGetServicePort categoryGetServicePort; + private final ArticleSaveServicePort articleSaveServicePort; + private final UserGetServicePort userGetServicePort; + private final CategorySaveServicePort categorySaveServicePort; + private final CategoryColorServicePort categoryColorServicePort; + private final ArticleDeleteServicePort articleDeleteServicePort; + + @Override + public void pushTest(PushTestRequest request) { + fcmService.sendNotification(request.fcmToken(), request.message()); + } + + @Override + public void createArticlesByCategory(User user, Long categoryId) { + String format = "%s:%s"; + Category category = categoryGetServicePort.findById(categoryId); + + for (int i = 0; i < 5; i++) { + Article article = Article.create( + String.format(format, user.getEmail(), UUID.randomUUID()), + "testMemo", + user, + category, + null + ); + articleSaveServicePort.save(article); + } + } + + @Override + public CategoriesTestResponse createCategories(User user) { + User getUser = userGetServicePort.findById(user.getId()); + List defaultCategoryNames = Arrays.asList( + "집", + "취업", + "동아리", + "자기계발", + "포트폴리오", + "경제시사흐름", + "최신기술트렌드", + "인성직무면접꿀팁", + "어학자격증취득준비", + "멘탈관리스트레스해소" + ); + + List createdCategoryNames = new ArrayList<>(); + Set usedColors = categoryColorServicePort.getUsedColorsByUser(getUser); + + for (int i = 0; i < 10; i++) { + String categoryName = defaultCategoryNames.get(i % defaultCategoryNames.size()); + if (i >= defaultCategoryNames.size()) { + categoryName = categoryName + "_" + (i - defaultCategoryNames.size() + 1); + } + + CategoryColor availableColor = getNextAvailableColor(usedColors); + Category category = Category.create(categoryName, getUser, availableColor); + Category savedCategory = categorySaveServicePort.save(category); + createdCategoryNames.add(savedCategory.getName()); + + // 사용된 색상 업데이트 + usedColors.add(availableColor); + } + + return CategoriesTestResponse.of(createdCategoryNames); + } + + private CategoryColor getNextAvailableColor(Set usedColors) { + return Arrays.stream(CategoryColor.values()) + .filter(color -> !usedColors.contains(color)) + .findFirst() + .orElse(CategoryColor.COLOR1); + } + + @Override + public void deleteArticlesByCategory(User user, Long categoryId) { + Category category = categoryGetServicePort.findById(categoryId); + User getUser = userGetServicePort.findById(user.getId()); + articleDeleteServicePort.deleteByCategory(getUser, category.getId()); + } +} From 6b0be221132d56c7a9746af239ef33a7218ff9fc Mon Sep 17 00:00:00 2001 From: rootTiket Date: Thu, 11 Sep 2025 23:26:51 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=20FCM=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=20=EC=96=B4=EB=8C=91=ED=84=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - FcmServicePort 구현체 - 기존 FcmService를 포트 패턴으로 연결 --- .../firebase/FcmServiceAdapter.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 infrastructure/src/main/java/com/pinback/infrastructure/firebase/FcmServiceAdapter.java diff --git a/infrastructure/src/main/java/com/pinback/infrastructure/firebase/FcmServiceAdapter.java b/infrastructure/src/main/java/com/pinback/infrastructure/firebase/FcmServiceAdapter.java new file mode 100644 index 0000000..d9480b3 --- /dev/null +++ b/infrastructure/src/main/java/com/pinback/infrastructure/firebase/FcmServiceAdapter.java @@ -0,0 +1,18 @@ +package com.pinback.infrastructure.firebase; + +import org.springframework.stereotype.Component; + +import com.pinback.application.test.port.out.FcmServicePort; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class FcmServiceAdapter implements FcmServicePort { + private final FcmService fcmService; + + @Override + public void sendNotification(String token, String message) { + fcmService.sendNotification(token, message); + } +} From 5d546a8f7bdfbfc243d6090c41246c3b4a544fdc Mon Sep 17 00:00:00 2001 From: rootTiket Date: Thu, 11 Sep 2025 23:27:05 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=20Test=20API=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - POST /api/v1/test/push: FCM 푸시 테스트 - POST /api/v1/test/articles: 카테고리별 아티클 생성 - POST /api/v1/test/categories: 카테고리 10개 생성 - DELETE /api/v1/test/articles/{categoryId}: 카테고리별 아티클 삭제 --- .../api/test/controller/TestController.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 api/src/main/java/com/pinback/api/test/controller/TestController.java diff --git a/api/src/main/java/com/pinback/api/test/controller/TestController.java b/api/src/main/java/com/pinback/api/test/controller/TestController.java new file mode 100644 index 0000000..a9c5072 --- /dev/null +++ b/api/src/main/java/com/pinback/api/test/controller/TestController.java @@ -0,0 +1,58 @@ +package com.pinback.api.test.controller; + +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.pinback.application.test.dto.request.PushTestRequest; +import com.pinback.application.test.dto.response.CategoriesTestResponse; +import com.pinback.application.test.port.in.TestPort; +import com.pinback.domain.user.entity.User; +import com.pinback.shared.annotation.CurrentUser; +import com.pinback.shared.dto.ResponseDto; + +import io.swagger.v3.oas.annotations.Parameter; +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/api/v1/test") +@RequiredArgsConstructor +public class TestController { + private final TestPort testPort; + + @PostMapping("/push") + public ResponseDto pushTest(@RequestBody PushTestRequest pushTestRequest) { + testPort.pushTest(pushTestRequest); + return ResponseDto.ok(); + } + + @PostMapping("/articles") + public ResponseDto createArticles( + @Parameter(hidden = true) @CurrentUser User user, + @RequestParam Long categoryId + ) { + testPort.createArticlesByCategory(user, categoryId); + return ResponseDto.ok(); + } + + @PostMapping("/categories") + public ResponseDto categoriesTest( + @Parameter(hidden = true) @CurrentUser User user + ) { + CategoriesTestResponse response = testPort.createCategories(user); + return ResponseDto.ok(response); + } + + @DeleteMapping("/articles/{categoryId}") + public ResponseDto deleteTest( + @Parameter(hidden = true) @CurrentUser User user, + @PathVariable Long categoryId + ) { + testPort.deleteArticlesByCategory(user, categoryId); + return ResponseDto.ok(); + } +} From 27c4795e69121dbfbf04140dec9d52ec19233f49 Mon Sep 17 00:00:00 2001 From: rootTiket Date: Thu, 11 Sep 2025 23:35:40 +0900 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20url=20=EC=B5=9C=EB=8C=80=20=EA=B8=B8?= =?UTF-8?q?=EC=9D=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/pinback/domain/article/entity/Article.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/com/pinback/domain/article/entity/Article.java b/domain/src/main/java/com/pinback/domain/article/entity/Article.java index 8956e0e..39d428c 100644 --- a/domain/src/main/java/com/pinback/domain/article/entity/Article.java +++ b/domain/src/main/java/com/pinback/domain/article/entity/Article.java @@ -40,7 +40,7 @@ public class Article extends BaseEntity { @Column(name = "article_id") private Long id; - @Column(name = "url", nullable = false) + @Column(name = "url", length = 700, nullable = false) private String url; @Column(name = "memo") From fadfafd656c94a7e2ab476e3b8a7c2af0b4d1970 Mon Sep 17 00:00:00 2001 From: rootTiket Date: Fri, 12 Sep 2025 00:11:42 +0900 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20=EC=A0=95=EB=A0=AC=EC=A1=B0=EA=B1=B4?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../article/repository/ArticleRepositoryCustomImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/src/main/java/com/pinback/infrastructure/article/repository/ArticleRepositoryCustomImpl.java b/infrastructure/src/main/java/com/pinback/infrastructure/article/repository/ArticleRepositoryCustomImpl.java index a1dc72d..e43a465 100644 --- a/infrastructure/src/main/java/com/pinback/infrastructure/article/repository/ArticleRepositoryCustomImpl.java +++ b/infrastructure/src/main/java/com/pinback/infrastructure/article/repository/ArticleRepositoryCustomImpl.java @@ -155,7 +155,7 @@ public RemindArticlesWithCount findTodayRemindWithCount(UUID userId, Pageable pa .where(conditions) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) - .orderBy(article.createdAt.desc()) + .orderBy(article.remindAt.asc()) .fetch(); JPAQuery countQuery = queryFactory