From 6530400bf7ecc0b14160fe7cfbc35ba208c998e6 Mon Sep 17 00:00:00 2001 From: yunrry Date: Wed, 20 Aug 2025 23:59:40 +0900 Subject: [PATCH 1/2] =?UTF-8?q?refactor:=20Post=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../airo/api/post/dto/PostCreateRequest.java | 47 ++++--------------- .../airo/api/post/dto/PostDetailResponse.java | 8 ++-- .../airo/api/post/dto/PostUpdateRequest.java | 7 +-- .../airo/cache/post/dto/PostCacheDto.java | 6 +-- .../java/backend/airo/domain/post/Post.java | 16 +++---- .../persistence/post/entity/PostEntity.java | 16 +++---- 6 files changed, 34 insertions(+), 66 deletions(-) diff --git a/src/main/java/backend/airo/api/post/dto/PostCreateRequest.java b/src/main/java/backend/airo/api/post/dto/PostCreateRequest.java index 556eaf7..f8c6502 100644 --- a/src/main/java/backend/airo/api/post/dto/PostCreateRequest.java +++ b/src/main/java/backend/airo/api/post/dto/PostCreateRequest.java @@ -2,6 +2,7 @@ import backend.airo.api.image.dto.ImageCreateRequest; import backend.airo.domain.post.enums.*; +import backend.airo.domain.post.vo.Location; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.Valid; import jakarta.validation.constraints.*; @@ -25,9 +26,10 @@ public record PostCreateRequest( @NotNull(message = "게시물 상태는 필수입니다") // @NotBlank → @NotNull PostStatus status, - @Schema(description = "누구와 태그", example = "FRIEND") - @NotNull(message = "withWhoTag는 필수입니다") // @NotBlank → @NotNull - PostWithWhoTag withWhoTag, + @Schema(description = "사업장 이름", example = "부산 맛집") + @Size(max = 100, message = "사업장 이름은 100자를 초과할 수 없습니다") // 길이 제한 추가 권장 + @NotNull(message = "상호명은 필수입니다") + String businessName, @Schema(description = "목적 태그", example = "HEALING") @NotNull(message = "forWhatTag는 필수입니다") // 필수라면 @NotNull 추가 @@ -48,6 +50,10 @@ public record PostCreateRequest( @PastOrPresent(message = "여행 날짜는 현재 또는 과거여야 합니다") LocalDate travelDate, + @Schema(description = "위치 정보", example = "{ \"latitude\": 35.1796, \"longitude\": 129.0756 }") + @Valid // Location 객체 검증을 위해 추가 + Location location, + @Schema(description = "주소", example = "부산시 해운대구") @Size(max = 500, message = "주소는 500자를 초과할 수 없습니다") // 길이 제한 추가 권장 String address, @@ -61,40 +67,5 @@ public record PostCreateRequest( Boolean isFeatured ) { - public static PostCreateRequest forDraft(String title, String content) { - return new PostCreateRequest( - title, content, PostStatus.DRAFT, - null, null, null, null, null, null, - List.of(), false - ); - } - - public static PostCreateRequest forPublish(String title, String content, - PostWithWhoTag withWhoTag, PostForWhatTag forWhatTag, - PostCategory category) { - return new PostCreateRequest( - title, content, PostStatus.PUBLISHED, - withWhoTag, forWhatTag, null, category, null, null, - List.of(), false - ); - } - - public boolean canPublish() { - return status == PostStatus.PUBLISHED - && title != null && !title.trim().isEmpty() - && content != null && !content.trim().isEmpty() - && withWhoTag != null - && emotionTags != null - && category != null; - } - - public boolean hasImages() { - return images != null && !images.isEmpty(); - } - - public boolean hasEmotionTags() { - return emotionTags != null && !emotionTags.isEmpty(); - } - } \ No newline at end of file diff --git a/src/main/java/backend/airo/api/post/dto/PostDetailResponse.java b/src/main/java/backend/airo/api/post/dto/PostDetailResponse.java index f2b2cd3..7db5f77 100644 --- a/src/main/java/backend/airo/api/post/dto/PostDetailResponse.java +++ b/src/main/java/backend/airo/api/post/dto/PostDetailResponse.java @@ -28,12 +28,12 @@ public record PostDetailResponse( @Schema(description = "게시물 요약", example = "부산에서의 즐거운 여행...") String summary, + @Schema(description = "사업장 이름", example = "짱구 분식") + String businessName, + @Schema(description = "게시물 상태", example = "PUBLISHED") PostStatus status, - @Schema(description = "누구와 태그", example = "FRIEND") - PostWithWhoTag withWhoTag, - @Schema(description = "목적 태그", example = "HEALING") PostForWhatTag forWhatTag, @@ -79,8 +79,8 @@ public static PostDetailResponse toResponse(Post post, post.getTitle(), post.getContent(), post.getSummary(), + post.getBusinessName(), post.getStatus(), - post.getWithWhoTag(), post.getForWhatTag(), post.getEmotionTags(), post.getTravelDate(), diff --git a/src/main/java/backend/airo/api/post/dto/PostUpdateRequest.java b/src/main/java/backend/airo/api/post/dto/PostUpdateRequest.java index 0d37c13..419f102 100644 --- a/src/main/java/backend/airo/api/post/dto/PostUpdateRequest.java +++ b/src/main/java/backend/airo/api/post/dto/PostUpdateRequest.java @@ -21,8 +21,6 @@ public record PostUpdateRequest( @Schema(description = "게시물 상태", example = "PUBLISHED") PostStatus status, - @Schema(description = "누구와 태그", example = "FRIEND") - PostWithWhoTag withWhoTag, @Schema(description = "목적 태그", example = "HEALING") PostForWhatTag forWhatTag, @@ -50,8 +48,7 @@ public record PostUpdateRequest( ) { public boolean hasChanges() { - return title != null || content != null || status != null || - withWhoTag != null || forWhatTag != null || emotionTags != null || + return title != null || content != null || status != null || forWhatTag != null || emotionTags != null || travelDate != null || location != null || address != null || isFeatured != null; } @@ -61,7 +58,7 @@ public boolean isStatusChange() { public boolean isMetadataOnly() { return title == null && content == null && - (withWhoTag != null || forWhatTag != null || emotionTags != null || + (forWhatTag != null || emotionTags != null || location != null || address != null || isFeatured != null); } } \ No newline at end of file diff --git a/src/main/java/backend/airo/cache/post/dto/PostCacheDto.java b/src/main/java/backend/airo/cache/post/dto/PostCacheDto.java index 548c257..416d08e 100644 --- a/src/main/java/backend/airo/cache/post/dto/PostCacheDto.java +++ b/src/main/java/backend/airo/cache/post/dto/PostCacheDto.java @@ -23,8 +23,8 @@ public class PostCacheDto { private String title; private String content; private String summary; + private String businessName; private PostStatus status; - private PostWithWhoTag withWhoTag; private PostForWhatTag forWhatTag; private PostCategory category; private LocalDate travelDate; @@ -44,8 +44,8 @@ public static PostCacheDto from(Post post) { post.getTitle(), post.getContent(), post.getSummary(), + post.getBusinessName(), post.getStatus(), - post.getWithWhoTag(), post.getForWhatTag(), post.getCategory(), post.getTravelDate(), @@ -64,7 +64,7 @@ public static PostCacheDto from(Post post) { public Post toPost() { return new Post( id, userId, title, content, summary, - status, withWhoTag, forWhatTag, + businessName,status, forWhatTag, emotionTags, category, travelDate, location, address, viewCount, likeCount, commentCount, isFeatured, publishedAt diff --git a/src/main/java/backend/airo/domain/post/Post.java b/src/main/java/backend/airo/domain/post/Post.java index f2233fa..2756186 100644 --- a/src/main/java/backend/airo/domain/post/Post.java +++ b/src/main/java/backend/airo/domain/post/Post.java @@ -23,8 +23,8 @@ public class Post { private String title; private String content; private String summary; + private String businessName; private PostStatus status; - private PostWithWhoTag withWhoTag; private PostForWhatTag forWhatTag; private List emotionTags; private PostCategory category; @@ -37,8 +37,8 @@ public class Post { private Boolean isFeatured = false; private LocalDateTime publishedAt; - public Post(Long id, Long userId, String title, String content, String summary, - PostStatus status, PostWithWhoTag withWhoTag, PostForWhatTag forWhatTag, + public Post(Long id, Long userId, String title, String content, String summary, String businessName, + PostStatus status, PostForWhatTag forWhatTag, List emotionTags, PostCategory category, LocalDate travelDate, Location location, String address, Integer viewCount, Integer likeCount, Integer commentCount, Boolean isFeatured, LocalDateTime publishedAt) { @@ -47,8 +47,8 @@ public Post(Long id, Long userId, String title, String content, String summary, this.title = title; this.content = content; this.summary = summary; + this.businessName = businessName; this.status = status; - this.withWhoTag = withWhoTag; this.forWhatTag = forWhatTag; this.emotionTags = emotionTags; this.category = category; @@ -78,8 +78,8 @@ public static Post createForTest( title, content, null, // summary + "gootshp", PostStatus.PUBLISHED, - PostWithWhoTag.ALLONE, PostForWhatTag.HEALING, emotionTags, category, @@ -101,13 +101,13 @@ public static Post createPost(PostCreateRequest request, Long userId) { request.title(), request.content(), null, // AI로 생성될 요약 + request.businessName(), request.status(), - request.withWhoTag(), request.forWhatTag(), request.emotionTags(), request.category(), request.travelDate(), - null, // 발행일은 별도 로직으로 처리 + request.location(), request.address(), 0, // 초기 조회수 0, // 초기 좋아요 수 @@ -124,8 +124,8 @@ public static Post updatePostFromCommand(Post existingPost, PostUpdateRequest re request.title() != null ? request.title() : existingPost.getTitle(), request.content() != null ? request.content() : existingPost.getContent(), existingPost.getSummary(), + existingPost.getBusinessName(), request.status() != null ? request.status() : existingPost.getStatus(), - request.withWhoTag() != null ? request.withWhoTag() : existingPost.getWithWhoTag(), request.forWhatTag() != null ? request.forWhatTag() : existingPost.getForWhatTag(), request.emotionTags() != null ? request.emotionTags() : existingPost.getEmotionTags(), existingPost.getCategory(), diff --git a/src/main/java/backend/airo/persistence/post/entity/PostEntity.java b/src/main/java/backend/airo/persistence/post/entity/PostEntity.java index 1d390cb..ddc366e 100644 --- a/src/main/java/backend/airo/persistence/post/entity/PostEntity.java +++ b/src/main/java/backend/airo/persistence/post/entity/PostEntity.java @@ -34,13 +34,13 @@ public class PostEntity extends BaseEntity { @Column(columnDefinition = "TEXT") private String summary; + @Column(columnDefinition = "TEXT") + private String businessName; + @Enumerated(EnumType.STRING) @Column(nullable = false) private PostStatus status = PostStatus.DRAFT; - @Enumerated(EnumType.STRING) - @Column(nullable = false) - private PostWithWhoTag withWhoTag = PostWithWhoTag.ALLONE; @Enumerated(EnumType.STRING) @Column(nullable = true) @@ -84,8 +84,8 @@ public class PostEntity extends BaseEntity { - public PostEntity(Long postId, Long userId, String title, String content, String summary, - PostStatus status, PostWithWhoTag withWhoTag, PostForWhatTag forWhatTag, + public PostEntity(Long postId, Long userId, String title, String content, String summary, String businessName, + PostStatus status, PostForWhatTag forWhatTag, List emotionTags, PostCategory category, LocalDate travelDate, Location location, String address, Boolean isFeatured, LocalDateTime publishedAt) { super(); this.id = postId; @@ -93,8 +93,8 @@ public PostEntity(Long postId, Long userId, String title, String content, String this.title = title; this.content = content; this.summary = summary; + this.businessName = businessName; this.status = status != null ? status : PostStatus.DRAFT; - this.withWhoTag = withWhoTag != null ? withWhoTag : PostWithWhoTag.ALLONE; this.forWhatTag = forWhatTag != null ? forWhatTag : PostForWhatTag.HEALING; this.emotionTags = emotionTags; this.category = category != null ? category : PostCategory.RESTAURANT; @@ -116,8 +116,8 @@ public static PostEntity toEntity(Post post) { post.getTitle(), post.getContent(), post.getSummary(), + post.getBusinessName(), post.getStatus(), - post.getWithWhoTag(), post.getForWhatTag(), post.getEmotionTags(), post.getCategory(), @@ -137,8 +137,8 @@ public static Post toDomain(PostEntity entity) { entity.getTitle(), entity.getContent(), entity.getSummary(), + entity.getBusinessName(), entity.getStatus(), - entity.getWithWhoTag(), entity.getForWhatTag(), entity.getEmotionTags(), entity.getCategory(), From 2851198255195b511f90c43c1b8b41fe805353d3 Mon Sep 17 00:00:00 2001 From: yunrry Date: Thu, 21 Aug 2025 00:38:32 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EB=82=B4=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=EB=AC=BC=20=EC=A1=B0=ED=9A=8C=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/swagger/PostControllerSwagger.java | 12 ++++++++++++ .../backend/airo/api/post/PostController.java | 14 ++++++++++++++ .../post/usecase/PostCacheUseCase.java | 7 ++++++- .../application/post/usecase/PostUseCase.java | 3 +++ .../post/query/GetPostListQueryService.java | 7 +++++++ .../domain/post/repository/PostRepository.java | 5 +++++ .../domain/user/repository/UserRepository.java | 6 ++++++ .../persistence/post/adapter/PostAdapter.java | 17 +++++++++++++++++ .../post/repository/PostJpaRepository.java | 6 ++++++ 9 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/main/java/backend/airo/api/global/swagger/PostControllerSwagger.java b/src/main/java/backend/airo/api/global/swagger/PostControllerSwagger.java index c831107..e243111 100644 --- a/src/main/java/backend/airo/api/global/swagger/PostControllerSwagger.java +++ b/src/main/java/backend/airo/api/global/swagger/PostControllerSwagger.java @@ -96,6 +96,18 @@ Response getPostSlice( + @Operation(summary = "내 게시물 조회", description = "사용자 나의 게시물 목록을 조회합니다.") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "게시물 목록 조회 성공", + content = @Content(schema = @Schema(implementation = PostListResponse.class))) + }) + @GetMapping + Response getMyPost( + @Valid @ModelAttribute PostListRequest request, + @UserPrincipal User user); + + @Operation(summary = "게시물 수정", description = "기존 게시물을 수정합니다.") @ApiResponses(value = { diff --git a/src/main/java/backend/airo/api/post/PostController.java b/src/main/java/backend/airo/api/post/PostController.java index 7f71465..6d93972 100644 --- a/src/main/java/backend/airo/api/post/PostController.java +++ b/src/main/java/backend/airo/api/post/PostController.java @@ -19,6 +19,8 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + @Slf4j @Validated @@ -101,6 +103,18 @@ public Response getPostSlice( } + @Override + @GetMapping("/my") + public Response getMyPost( + @Valid @ModelAttribute PostListRequest request, + @UserPrincipal User user) { + + PostListResponse response = postUseCase.getMyPostList(request, user.getId()); + + return Response.success(response); + } + + // ===== 게시물 수정 ===== @Override diff --git a/src/main/java/backend/airo/application/post/usecase/PostCacheUseCase.java b/src/main/java/backend/airo/application/post/usecase/PostCacheUseCase.java index 843c6b8..6b91b8c 100644 --- a/src/main/java/backend/airo/application/post/usecase/PostCacheUseCase.java +++ b/src/main/java/backend/airo/application/post/usecase/PostCacheUseCase.java @@ -43,7 +43,7 @@ public class PostCacheUseCase { private final DeletePostCommandService deletePostCommandService; private final UpsertPointCommand upsertPointCommand; private final CreatePointHistoryCommand createPointHistoryCommand; - + private final GetPostListQueryService getPostListQueryService; private final GetPostQueryService getPostQueryService; private final GetUserQuery getUserQueryService; private final GetImageQueryService getImageQueryService; @@ -160,6 +160,11 @@ public void deletePost(Long postId, Long requesterId) { } + public PostListResponse getMyPostList(PostListRequest request, Long userId) { + Page posts = getPostListQueryService.handleMyPosts(request, userId); + PostListResponse postListResponse = PostListResponse.fromDomain(posts); + return postListResponse; + } // private method diff --git a/src/main/java/backend/airo/application/post/usecase/PostUseCase.java b/src/main/java/backend/airo/application/post/usecase/PostUseCase.java index bebdb69..0b464fb 100644 --- a/src/main/java/backend/airo/application/post/usecase/PostUseCase.java +++ b/src/main/java/backend/airo/application/post/usecase/PostUseCase.java @@ -66,6 +66,9 @@ public Post createPost(PostCreateRequest request, Long userId) { } + + + public PostDetailResponse getPostDetail(Long postId, Long requesterId) { log.debug("게시물 조회: id={}, requesterId={}", postId, requesterId); Post post = getPostQueryService.handle(postId); diff --git a/src/main/java/backend/airo/domain/post/query/GetPostListQueryService.java b/src/main/java/backend/airo/domain/post/query/GetPostListQueryService.java index 8e393df..e9cc2c5 100644 --- a/src/main/java/backend/airo/domain/post/query/GetPostListQueryService.java +++ b/src/main/java/backend/airo/domain/post/query/GetPostListQueryService.java @@ -23,6 +23,12 @@ public Page handle(PostListRequest request) { return retrievePosts(request.sortBy(), pageable, request.status()); } + public Page handleMyPosts(PostListRequest request, Long userId) { + Pageable pageable = buildPageable(request); + return postRepository.findByUserId(userId, pageable); + } + + public Slice handleSlice(PostSliceRequest request) { log.debug("무한스크롤 게시물 조회: lastPostId={}, size={}", request.lastPostId(), request.size()); @@ -32,6 +38,7 @@ public Slice handleSlice(PostSliceRequest request) { } + private Pageable buildPageable(PostListRequest request) { Sort sort = determineSort(request.sortBy()); return PageRequest.of(request.page(), request.size(), sort); diff --git a/src/main/java/backend/airo/domain/post/repository/PostRepository.java b/src/main/java/backend/airo/domain/post/repository/PostRepository.java index 48f7122..d7c3fed 100644 --- a/src/main/java/backend/airo/domain/post/repository/PostRepository.java +++ b/src/main/java/backend/airo/domain/post/repository/PostRepository.java @@ -54,4 +54,9 @@ Page findByStatus( Long findMaxPostId(); boolean existsByIdLessThan(Long postId); + + Page findByUserId( + Long userId, + Pageable pageable + ); } \ No newline at end of file diff --git a/src/main/java/backend/airo/domain/user/repository/UserRepository.java b/src/main/java/backend/airo/domain/user/repository/UserRepository.java index 35d9fa0..80c7a37 100644 --- a/src/main/java/backend/airo/domain/user/repository/UserRepository.java +++ b/src/main/java/backend/airo/domain/user/repository/UserRepository.java @@ -1,8 +1,12 @@ package backend.airo.domain.user.repository; import backend.airo.domain.AggregateSupport; +import backend.airo.domain.post.Post; import backend.airo.domain.user.User; import backend.airo.domain.user.enums.ProviderType; +import backend.airo.persistence.post.entity.PostEntity; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import java.util.Optional; @@ -15,4 +19,6 @@ public interface UserRepository extends AggregateSupport { // User와 연관된 모든 데이터를 함께 삭제 void deleteUserWithRelatedData(Long userId); + + } diff --git a/src/main/java/backend/airo/persistence/post/adapter/PostAdapter.java b/src/main/java/backend/airo/persistence/post/adapter/PostAdapter.java index 12a09d9..9a7e52f 100644 --- a/src/main/java/backend/airo/persistence/post/adapter/PostAdapter.java +++ b/src/main/java/backend/airo/persistence/post/adapter/PostAdapter.java @@ -197,6 +197,20 @@ public boolean existsByIdLessThan(Long id) { return postJpaRepository.existsByIdLessThan(id); } + + + @Override + public Page findByUserId(Long userId, Pageable pageable) { + log.debug("사용자 ID로 게시물 조회: userId={}, 페이지: {}", userId, pageable); + Page entities = postJpaRepository.findByUserId(userId, pageable); + return entities.map(PostEntity::toDomain); + } + + + + + + // ===== Private Helper Methods ===== private PostEntity updateExistingEntity(Post post) { @@ -205,4 +219,7 @@ private PostEntity updateExistingEntity(Post post) { return PostEntity.toEntity(post); } + + + } \ No newline at end of file diff --git a/src/main/java/backend/airo/persistence/post/repository/PostJpaRepository.java b/src/main/java/backend/airo/persistence/post/repository/PostJpaRepository.java index e497d63..0a69b9e 100644 --- a/src/main/java/backend/airo/persistence/post/repository/PostJpaRepository.java +++ b/src/main/java/backend/airo/persistence/post/repository/PostJpaRepository.java @@ -71,4 +71,10 @@ Slice findByStatusAndIdLessThanOrderByIdDesc( boolean existsByIdLessThan(@Param("postId") Long postId); void deleteByUserId(Long userId); + + + Page findByUserId( + Long userId, + Pageable pageable + ); }