Repository: KEA-ChunSam/PlayUs-community-service
Pull request #23: Feat: 커뮤니티 글 API 구현
Author: login: gachaemin
Labels: name: ✨ feature
description: 새로운 기능
name: 채민
Created: 2025-05-12T05:29:53Z | Merged: 2025-05-16T00:53:00Z

1. 커뮤니티 글 작성 API 구현
2. 커뮤니티 글 수정 API 구현
3. 커뮤니티 글 삭제 API 구현

## ✅ PR 유형
어떤 변경 사항이 있었나요?

- [x] 새로운 기능 추가
- [ ] 버그 수정
- [ ] 리팩토링
- [ ] 코드에 영향을 주지 않는 변경사항(주석, 개행 등등..)
- [ ] 문서 수정
- [ ] 빌드 부분 혹은 패키지 매니저 수정
- [ ] 테스트 코드 추가

---

## ✏️ 작업 내용
![image](https://github.com/user-attachments/assets/4f799299-a7a3-479f-901b-e9b6c2aa0e9c)
요청을 받는 PostController 파일입니다.

![image](https://github.com/user-attachments/assets/150c82b8-9b7b-4078-b003-3cf3d823790b)
비즈니스 로직 분리를 위한 PostService 파일입니다.

![image](https://github.com/user-attachments/assets/36522696-7d17-46e6-b94b-1f7d20b595c9)
dto파일의 구조입니다.

![image](https://github.com/user-attachments/assets/46e5afd1-3cfb-434c-9ea2-03b36cdacdd8)
![image](https://github.com/user-attachments/assets/f11b0da1-9c04-4072-8033-526fc0d065f3)
각각 Request/Response 파일의 예시입니다.

![image](https://github.com/user-attachments/assets/220f5ec1-7cf8-4467-b4ad-5cd82ca659a3)
API 문서화를 위한 Swagger 명세 인터페이스 코드입니다.

---

## 🔗 관련 이슈
- closes #22 

---

## 💡 추가 사항

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **신규 기능**
  - 게시글 생성, 수정, 삭제를 위한 REST API 엔드포인트가 추가되었습니다.
  - 게시글 생성, 삭제, 수정 요청 및 응답 데이터 구조가 도입되었습니다.
  - JWT 기반 인증 및 권한 관리 기능이 도입되어 보안이 강화되었습니다.
  - CORS 설정이 추가되어 특정 도메인에서의 API 접근이 허용됩니다.
  - WebSocket 및 보안 관련 의존성이 추가되었습니다.

- **문서화**
  - 게시글 관련 API에 대한 Swagger(OpenAPI) 문서가 추가되어 요청 및 응답 예시와 설명이 제공됩니다.

- **버그 수정 및 개선**
  - Redis 자동 구성 기능이 비활성화되어 불필요한 리소스 사용이 줄어들었습니다.
  - 예외 처리 로직이 개선되어 다양한 오류 상황에 대해 일관된 응답과 로깅이 제공됩니다.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Linked issue #22: CS-250 Feat/Post API 구현
### 상위 작업 (Epic, 보라색 번개) Ticket Number

CS-20

### 이슈 내용 (Description)

커뮤니티 글에 관련된 API 구현

### 담당자 이름

_No response_

### 상세 내용 (Details)

- About Details


### 체크리스트 (Tasks)

- [ ] Tasks1
- [ ] Tasks2


### 참조 (References)

- Reference1


Diff:
diff --git a/build.gradle b/build.gradle
index 1d5a399..01f7d17 100644
--- a/build.gradle
+++ b/build.gradle
@@ -31,6 +31,9 @@ dependencies {
 	// Spring
 	implementation 'org.springframework.boot:spring-boot-starter-web'
 	implementation 'org.springframework.boot:spring-boot-starter-validation'
+	implementation 'org.springframework.boot:spring-boot-starter-websocket'
+	implementation 'org.springframework.boot:spring-boot-starter-security'
+	implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.12.0' // for StringUtils
 
 	// DB
 //	implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc'
@@ -66,6 +69,11 @@ dependencies {
 	// Sentry
 	implementation("io.sentry:sentry-logback:7.17.0")
 	implementation("com.github.maricn:logback-slack-appender:1.6.1")
+
+	//JWT
+	implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
+	runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5'
+	runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5'
 }
 
 dependencyManagement {
diff --git a/src/main/java/com/playus/communityservice/CommunityServiceApplication.java b/src/main/java/com/playus/communityservice/CommunityServiceApplication.java
index 1bbe571..d3ec399 100644
--- a/src/main/java/com/playus/communityservice/CommunityServiceApplication.java
+++ b/src/main/java/com/playus/communityservice/CommunityServiceApplication.java
@@ -3,7 +3,11 @@
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 
-@SpringBootApplication
+
+@SpringBootApplication(exclude = {
+		org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.class,
+		org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration.class
+})
 public class CommunityServiceApplication {
 
 	public static void main(String[] args) {
diff --git a/src/main/java/com/playus/communityservice/domain/post/controller/PostController.java b/src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
new file mode 100644
index 0000000..0747aad
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
@@ -0,0 +1,51 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.domain.post.specification.PostControllerSpecification;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController implements PostControllerSpecification {
+
+    private final PostService postService;
+
+    @PostMapping("/{tag}")
+    public ResponseEntity<PostCreateResponse> createPost(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostCreateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostCreateResponse response = postService.createPost(request, user, tag);
+        URI location = URI.create("/post/" + response.postId());
+        return ResponseEntity.created(location).body(response);
+    }
+
+    @PatchMapping("/{tag}")
+    public ResponseEntity<PostUpdateResponse> updatePost(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostUpdateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostUpdateResponse response = postService.updatePost(request, user, tag);
+        return ResponseEntity.ok(response);
+    }
+
+    @DeleteMapping
+    public ResponseEntity<PostDeleteResponse> deletePost(@Valid @RequestBody PostDeleteRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostDeleteResponse response = postService.deletePost(request, user);
+        return ResponseEntity.ok(response);
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/document/PostDocument.java b/src/main/java/com/playus/communityservice/domain/post/document/PostDocument.java
index 1e5c4e5..1e83de8 100644
--- a/src/main/java/com/playus/communityservice/domain/post/document/PostDocument.java
+++ b/src/main/java/com/playus/communityservice/domain/post/document/PostDocument.java
@@ -1,11 +1,13 @@
 package com.playus.communityservice.domain.post.document;
 
-import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.enums.TeamTag;
 import jakarta.validation.constraints.*;
 import lombok.*;
 import org.springframework.data.annotation.Id;
 import org.springframework.data.mongodb.core.mapping.*;
 
+import java.time.LocalDate;
+
 @Getter
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
 @Document(value = "post")
@@ -23,7 +25,7 @@ public class PostDocument {
     private String title;
 
     @NotNull
-    private Tag tag;
+    private TeamTag tag;
 
     @NotNull
     private String description;
@@ -35,9 +37,12 @@ public class PostDocument {
     @Field(name = "is_secret")
     private boolean isSecret;
 
+    @Field(name = "jwp_date")
+    private LocalDate jwpDate;
+
 
     @Builder
-    private PostDocument(Long id, String title, String description, Tag tag, Long writerId, boolean activated, boolean isSecret) {
+    private PostDocument(Long id, String title, String description, TeamTag tag, Long writerId, boolean activated, boolean isSecret) {
         this.id = id;
         this.title = title;
         this.description = description;
@@ -47,7 +52,7 @@ private PostDocument(Long id, String title, String description, Tag tag, Long wr
         this.isSecret = isSecret;
     }
 
-    public static PostDocument createForOnlyTest(Long id, Long writerId, String title, String description, Tag tag) {
+    public static PostDocument createForOnlyTest(Long id, Long writerId, String title, String description, TeamTag tag) {
         return PostDocument.builder()
                 .id(id)
                 .writerId(writerId)
diff --git a/src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java b/src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java
new file mode 100644
index 0000000..dc5a01c
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java
@@ -0,0 +1,35 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.validation.constraints.*;
+import lombok.Builder;
+import java.time.LocalDate;
+
+@Builder
+public record PostCreateRequest(
+
+        @NotBlank(message = "게시글 제목이 비어 있습니다!")
+        @Size(min= 1, max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        String title,
+
+        @Size(max = 255)
+        String image,
+
+        @NotBlank(message = "본문이 비어 있습니다!")
+        @Size(min = 1, max = 500, message = "본문의 길이를 1~500자 이내로 작성해 주세요!")
+        String content,
+
+        @JsonFormat(pattern = "yyyy-MM-dd")
+        LocalDate jwpDate
+
+) {
+
+    public static PostCreateRequest of(String title, String image , String content, LocalDate jwpDate) {
+        return PostCreateRequest.builder()
+                .title(title)
+                .image(image)
+                .content(content)
+                .jwpDate(jwpDate)
+                .build();
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java b/src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
new file mode 100644
index 0000000..12699f0
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
@@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import lombok.Builder;
+
+@Builder
+public record PostCreateResponse(
+        Long postId,
+        String message
+) {
+
+    public static PostCreateResponse of(Long postId, String message) {
+        return PostCreateResponse.builder()
+                .postId(postId)
+                .message(message)
+                .build();
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteRequest.java b/src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteRequest.java
new file mode 100644
index 0000000..bd56886
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteRequest.java
@@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_delete;
+
+import jakarta.validation.constraints.NotNull;
+import lombok.Builder;
+
+@Builder
+public record PostDeleteRequest(
+
+        @NotNull(message = "postID는 null일 수 없습니다!")
+        Long postId
+) {
+    public static PostDeleteRequest of(Long postId) {
+        return PostDeleteRequest.builder()
+                .postId(postId)
+                .build();
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java b/src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java
new file mode 100644
index 0000000..11bcf96
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java
@@ -0,0 +1,16 @@
+package com.playus.communityservice.domain.post.dto.post_delete;
+
+import lombok.Builder;
+
+@Builder
+public record PostDeleteResponse(
+        boolean success,
+        String message
+) {
+    public static PostDeleteResponse of(boolean success, String message) {
+        return PostDeleteResponse.builder()
+                .success(success)
+                .message(message)
+                .build();
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateRequest.java b/src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateRequest.java
new file mode 100644
index 0000000..57c094c
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateRequest.java
@@ -0,0 +1,41 @@
+package com.playus.communityservice.domain.post.dto.post_update;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Builder;
+
+import java.time.LocalDate;
+
+@Builder
+public record PostUpdateRequest(
+
+        @NotNull(message = "postID는 null일 수 없습니다!")
+        Long postId,
+
+        @NotBlank(message = "게시글 제목이 비어 있습니다!")
+        @Size(max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        String title,
+
+        @Size(max = 255)
+        String image,
+
+        @NotBlank(message = "본문이 비어 있습니다!")
+        @Size(max = 500, message = "본문의 길이를 1~500자 이내로 작성해 주세요!")
+        String content,
+
+        @JsonFormat(pattern = "yyyy-MM-dd")
+        LocalDate jwpDate
+) {
+
+    public static PostUpdateRequest of(Long postId, String title, String image, String content, LocalDate jwpDate) {
+        return PostUpdateRequest.builder()
+                .postId(postId)
+                .title(title)
+                .image(image)
+                .content(content)
+                .jwpDate(jwpDate)
+                .build();
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java b/src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java
new file mode 100644
index 0000000..4ffb04f
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java
@@ -0,0 +1,16 @@
+package com.playus.communityservice.domain.post.dto.post_update;
+
+import lombok.Builder;
+
+@Builder
+public record PostUpdateResponse(
+        boolean success,
+        String message
+) {
+    public static PostUpdateResponse of(boolean success, String message) {
+        return PostUpdateResponse.builder()
+                .success(success)
+                .message(message)
+                .build();
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/entity/Post.java b/src/main/java/com/playus/communityservice/domain/post/entity/Post.java
index d28ca21..5a9229a 100644
--- a/src/main/java/com/playus/communityservice/domain/post/entity/Post.java
+++ b/src/main/java/com/playus/communityservice/domain/post/entity/Post.java
@@ -1,10 +1,12 @@
 package com.playus.communityservice.domain.post.entity;
 
 import com.playus.communityservice.domain.common.BaseTimeEntity;
-import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.enums.TeamTag;
 import jakarta.persistence.*;
 import lombok.*;
 
+import java.time.LocalDate;
+
 @Entity
 @Getter
 @NoArgsConstructor(access = AccessLevel.PROTECTED)
@@ -23,7 +25,10 @@ public class Post extends BaseTimeEntity {
 
     @Enumerated(EnumType.STRING)
     @Column(nullable = false)
-    private Tag tag;
+    private TeamTag tag;
+
+    @Column(name = "jwp_date")
+    private LocalDate jwpDate;
 
     @Column(columnDefinition = "TEXT", nullable = false)
     private String description;
@@ -36,16 +41,17 @@ public class Post extends BaseTimeEntity {
 
 
     @Builder
-    private Post(String title, String description, Tag tag, Long writerId, boolean activated, boolean isSecret) {
+    private Post(String title, String description, TeamTag tag, Long writerId, boolean activated, boolean isSecret, LocalDate jwpDate) {
         this.title = title;
         this.description = description;
         this.tag = tag;
         this.writerId = writerId;
         this.activated = activated;
         this.isSecret = isSecret;
+        this.jwpDate = jwpDate;
     }
 
-    public static Post create(final Long writerId, final String title, final String description, final Tag tag) {
+    public static Post create(final Long writerId, final String title, final String description, final TeamTag tag, final LocalDate jwpDate) {
         return Post.builder()
                 .writerId(writerId)
                 .title(title)
@@ -53,14 +59,16 @@ public static Post create(final Long writerId, final String title, final String
                 .tag(tag)
                 .activated(true)
                 .isSecret(false)
+                .jwpDate(jwpDate)
                 .build();
     }
 
-    public void updateAll(final String title, final String description, final Tag tag, final boolean isSecret) {
+    public void updateAll(final String title, final String description, final TeamTag tag, final boolean isSecret, final LocalDate jwpDate) {
         this.title = title;
         this.description = description;
         this.tag = tag;
         this.isSecret = isSecret;
+        this.jwpDate = jwpDate;
     }
 
     public void delete() {
diff --git a/src/main/java/com/playus/communityservice/domain/post/enums/Tag.java b/src/main/java/com/playus/communityservice/domain/post/enums/Tag.java
deleted file mode 100644
index 01ae7b8..0000000
--- a/src/main/java/com/playus/communityservice/domain/post/enums/Tag.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.playus.communityservice.domain.post.enums;
-
-public enum Tag {
-    DOOSAN_BEARS,
-    HANWHA_EAGLES,
-    KIA_TIGERS,
-    KIWOOM_HEROES,
-    LG_TWINS,
-    LOTTE_GIANTS,
-    NC_DINOS,
-    SSG_LANDERS,
-    SAMSUNG_LIONS,
-    KT_WIZ
-}
diff --git a/src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java b/src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java
new file mode 100644
index 0000000..6331db1
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java
@@ -0,0 +1,28 @@
+package com.playus.communityservice.domain.post.enums;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public enum TeamTag {
+    DOOSAN_BEARS("두산 베어스"),
+    HANWHA_EAGLES("한화 이글스"),
+    KIA_TIGERS("KIA 타이거즈"),
+    KIWOOM_HEROES("키움 히어로즈"),
+    LG_TWINS("LG 트윈스"),
+    LOTTE_GIANTS("롯데 자이언츠"),
+    NC_DINOS("NC 다이노스"),
+    SSG_LANDERS("SSG 랜더스"),
+    SAMSUNG_LIONS("삼성 라이온즈"),
+    KT_WIZ("KT 위즈"),;
+
+    private final String teamName;
+
+    public static TeamTag fromString(String name){
+        for (TeamTag teamTag : TeamTag.values()) {
+            if (teamTag.teamName.equals(name)) {
+                return teamTag;
+            }
+        }
+        throw new IllegalArgumentException("No enum constant " + name);
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/repository/write/PostImageRepository.java b/src/main/java/com/playus/communityservice/domain/post/repository/write/PostImageRepository.java
new file mode 100644
index 0000000..8316eda
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/repository/write/PostImageRepository.java
@@ -0,0 +1,7 @@
+package com.playus.communityservice.domain.post.repository.write;
+
+import com.playus.communityservice.domain.post.entity.PostImage;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+public interface PostImageRepository extends JpaRepository<PostImage, Long> {
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/service/PostService.java b/src/main/java/com/playus/communityservice/domain/post/service/PostService.java
new file mode 100644
index 0000000..e27044c
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/service/PostService.java
@@ -0,0 +1,58 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import com.playus.communityservice.global.exception.EntityNotFoundException;
+import com.playus.communityservice.global.exception.UnauthorizedAccessException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+
+    @Transactional
+    public PostCreateResponse createPost(PostCreateRequest request, JwtUser user, TeamTag tag) {
+        Post post = Post.create(user.getId(), request.title(), request.content(), tag, request.jwpDate());
+        postRepository.save(post);
+
+        return PostCreateResponse.of(post.getId(), "게시물 생성이 완료되었습니다.");
+    }
+
+    @Transactional
+    public PostUpdateResponse updatePost(PostUpdateRequest request, JwtUser user, TeamTag tag) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new EntityNotFoundException("게시글"));
+
+        if (!post.getWriterId().equals(user.getId())) {
+            throw new UnauthorizedAccessException("게시글");
+        }
+
+        post.updateAll(request.title(), request.content(), tag, false, request.jwpDate());
+        return PostUpdateResponse.of(true, "게시물이 수정되었습니다.");
+    }
+
+    @Transactional
+    public PostDeleteResponse deletePost(PostDeleteRequest request, JwtUser user) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new EntityNotFoundException("게시글"));
+
+        if (!post.getWriterId().equals(user.getId())) {
+            throw new UnauthorizedAccessException("게시글");
+        }
+
+        post.delete();
+        return PostDeleteResponse.of(true, "게시물이 삭제되었습니다.");
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java b/src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
new file mode 100644
index 0000000..ee3e8eb
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
@@ -0,0 +1,158 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            security = @SecurityRequirement(name = "AccessCookie"),
+            parameters = @Parameter(
+                    name = "Access",
+                    description = "JWT access token (쿠키)",
+                    in = ParameterIn.COOKIE,
+                    required = true,
+                    example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
+            ),
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!",
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "201", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : true,
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1,
+                                      "jwpDate" : "2025-05-01"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "수정 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "수정 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : true,
+                                        "message" : "게시물이 수정되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostUpdateResponse> updatePost(TeamTag tag, PostUpdateRequest request, JwtUser user);
+}
+
diff --git a/src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java b/src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
new file mode 100644
index 0000000..7bd12f7
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
@@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
+
+        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+        if (header != null && header.startsWith("Bearer ")) {
+            String token = header.substring(7);
+            try {
+                if (!jwtUtil.isExpired(token)) {
+                    Long userId = Long.parseLong(jwtUtil.getUserId(token));
+                    String role = jwtUtil.getRole(token);
+
+                    JwtUser jwtUser = new JwtUser(userId, role);
+                    Authentication auth = new UsernamePasswordAuthenticationToken(
+                            jwtUser, null, jwtUser.getAuthorities()
+                    );
+                    SecurityContextHolder.getContext().setAuthentication(auth);
+                }
+            } catch (JwtException | IllegalArgumentException e) {
+                log.debug("JWT 인증 실패: {}", e.getMessage());
+            }
+        }
+
+        chain.doFilter(request, response);
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java b/src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java
new file mode 100644
index 0000000..4664ff6
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java
@@ -0,0 +1,42 @@
+package com.playus.communityservice.global.config.jwt;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+@Getter
+@AllArgsConstructor
+public class JwtUser implements UserDetails {
+    private final Long userId;
+    private final String role;
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return null;
+    }
+
+    @Override
+    public String getPassword() { return null; }
+
+    @Override
+    public String getUsername() { return String.valueOf(userId); }
+
+    @Override
+    public boolean isAccountNonExpired() { return true; }
+
+    @Override
+    public boolean isAccountNonLocked() { return true; }
+
+    @Override
+    public boolean isCredentialsNonExpired() { return true; }
+
+    @Override
+    public boolean isEnabled() { return true; }
+
+    public Long getId() {
+        return userId;
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/global/config/jwt/JwtUtil.java b/src/main/java/com/playus/communityservice/global/config/jwt/JwtUtil.java
new file mode 100644
index 0000000..f9f7d1b
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/config/jwt/JwtUtil.java
@@ -0,0 +1,84 @@
+package com.playus.communityservice.global.config.jwt;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import javax.crypto.SecretKey;
+import java.util.Date;
+import java.util.UUID;
+
+
+@Component
+public class JwtUtil {
+
+    private final SecretKey key;
+    public static final long ACCESS_EXPIRE_MS  = 6 * 60 * 60 * 1000;      // 6시간
+    public static final long REFRESH_EXPIRE_MS = 7L * 24 * 60 * 60 * 1000; // 7일
+
+    public JwtUtil(@Value("${spring.jwt.secret}") String secret) {
+        byte[] byteSecretKey = Decoders.BASE64.decode(secret);
+        this.key = Keys.hmacShaKeyFor(byteSecretKey);
+    }
+
+    //엑세스토큰
+    public String createAccessToken(String userId, String role) {
+        return Jwts.builder()
+                .setId(UUID.randomUUID().toString())
+                .setSubject(userId)
+                .claim("role", role)
+                .claim("type", "access")
+                .setIssuedAt(new Date())
+                .setExpiration(new Date(System.currentTimeMillis() + ACCESS_EXPIRE_MS))
+                .signWith(key)
+                .compact();
+    }
+
+    //리프레시토큰
+    public String createRefreshToken(String userId, String role) {
+        return Jwts.builder()
+                .setSubject(userId)
+                .claim("role", role)
+                .claim("type", "refresh")
+                .setIssuedAt(new Date())
+                .setExpiration(new Date(System.currentTimeMillis() + REFRESH_EXPIRE_MS))
+                .signWith(key)
+                .compact();
+    }
+
+    public Boolean isExpired(String token) {
+        Date expiration = extractPayload(token).getExpiration();
+        return expiration.before(new Date());
+    }
+
+    public String getUserId(String token) {
+        return extractPayload(token).getSubject();
+    }
+
+    public String getRole(String token) {
+        return extractPayload(token).get("role", String.class);
+    }
+
+    private Claims extractPayload(String token) {
+        return Jwts
+                .parserBuilder()
+                .setSigningKey(key)
+                .build()
+                .parseClaimsJws(token)
+                .getBody();
+    }
+
+    public String getJti(String token) {
+        return extractPayload(token).getId();
+    }
+
+    public String getType(String token) {
+        return extractPayload(token).get("type", String.class);
+    }
+
+    public long getRemainingExpirationTime(String token) {
+        return extractPayload(token).getExpiration().getTime() - System.currentTimeMillis();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/playus/communityservice/global/config/security/CorsConfig.java b/src/main/java/com/playus/communityservice/global/config/security/CorsConfig.java
new file mode 100644
index 0000000..362054c
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/config/security/CorsConfig.java
@@ -0,0 +1,35 @@
+package com.playus.communityservice.global.config.security;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+
+import java.util.List;
+
+@Configuration
+public class CorsConfig {
+
+    @Bean("corsConfigurationSource")
+    public org.springframework.web.cors.CorsConfigurationSource corsConfigurationSource() {
+        CorsConfiguration configuration = new CorsConfiguration();
+
+        configuration.setAllowedOrigins(List.of(
+                "http://localhost:3000"
+        ));
+        configuration.addAllowedHeader("*");
+
+        configuration.addAllowedMethod(HttpMethod.GET.name());
+        configuration.addAllowedMethod(HttpMethod.POST.name());
+        configuration.addAllowedMethod(HttpMethod.PUT.name());
+        configuration.addAllowedMethod(HttpMethod.DELETE.name());
+        configuration.addAllowedMethod(HttpMethod.OPTIONS.name());
+
+        configuration.setAllowCredentials(true);
+
+        org.springframework.web.cors.UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", configuration);
+        return source;
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/global/config/security/SecurityConfig.java b/src/main/java/com/playus/communityservice/global/config/security/SecurityConfig.java
new file mode 100644
index 0000000..5af50a9
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/config/security/SecurityConfig.java
@@ -0,0 +1,59 @@
+package com.playus.communityservice.global.config.security;
+
+import com.playus.communityservice.global.config.jwt.JwtFilter;
+import com.playus.communityservice.global.config.jwt.JwtUtil;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.web.cors.CorsConfigurationSource;
+
+@Configuration
+@EnableWebSecurity
+@RequiredArgsConstructor
+public class SecurityConfig {
+
+    private final JwtUtil jwtUtil;
+    private final CorsConfigurationSource corsConfigurationSource;
+
+    private String [] getWhiteList() {
+        return new String[] {
+                "/swagger",
+                "/swagger-ui.html",
+                "/swagger-ui/**",
+                "/api-docs",
+                "/api-docs/**",
+                "/v3/api-docs/**",
+        };
+    }
+
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+        http.csrf(AbstractHttpConfigurer::disable);
+        http.formLogin(AbstractHttpConfigurer::disable);
+        http.httpBasic(AbstractHttpConfigurer::disable);
+        http.cors((httpSecurityCorsConfigurer -> httpSecurityCorsConfigurer.configurationSource(corsConfigurationSource)));
+        http.addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class);
+        http.authorizeHttpRequests(auth -> auth
+                .requestMatchers(getWhiteList()).permitAll()
+                .anyRequest().authenticated()
+        );
+
+        // 세션 관리: Stateless
+        http.sessionManagement(session -> session
+                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+        );
+
+        return http.build();
+
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/playus/communityservice/global/exception/EntityNotFoundException.java b/src/main/java/com/playus/communityservice/global/exception/EntityNotFoundException.java
new file mode 100644
index 0000000..9dd6ea2
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/exception/EntityNotFoundException.java
@@ -0,0 +1,7 @@
+package com.playus.communityservice.global.exception;
+
+public class EntityNotFoundException extends RuntimeException {
+    public EntityNotFoundException(String entityName) {
+        super(entityName + "을(를) 찾을 수 없습니다.");
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java b/src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
new file mode 100644
index 0000000..184aa8e
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
@@ -0,0 +1,64 @@
+package com.playus.communityservice.global.exception;
+
+import com.playus.communityservice.domain.post.controller.PostController;
+import com.playus.communityservice.global.response.ErrorResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.server.ResponseStatusException;
+
+
+@Slf4j
+@RestControllerAdvice(assignableTypes = {
+        PostController.class
+})
+public class ExceptionAdvice {
+
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(BindException.class)
+    public ErrorResponse bindExceptionHandler(BindException e) {
+        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
+        log.warn("Validation Error: {}", errorMessage);
+        return ErrorResponse.badRequestError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.UNAUTHORIZED)
+    @ExceptionHandler(ResponseStatusException.class)
+    public ErrorResponse responseStatusExHandler(ResponseStatusException e) {
+        String errorMessage = e.getMessage();
+        log.warn("INVALID_TOKEN Error: {}", errorMessage);
+        return ErrorResponse.unauthorizedError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.NOT_FOUND)
+    @ExceptionHandler({
+            EntityNotFoundException.class
+    })
+    public ErrorResponse handleEntityNotFoundException(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Entity Not Found Error: {}", errorMessage);
+        return ErrorResponse.notFoundError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.FORBIDDEN)
+    @ExceptionHandler({
+            UnauthorizedAccessException.class
+    })
+    public ErrorResponse handleUnauthorizedAccessException(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Unauthorized Access Error: {}", errorMessage);
+        return ErrorResponse.forbiddenError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    @ExceptionHandler(Exception.class)
+    public ErrorResponse otherExceptionHandler(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Unexpected Error: {}", errorMessage);
+        return ErrorResponse.internalServerError("서버 에러가 발생했습니다! 관리자에게 문의해 주세요!");
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/global/exception/UnauthorizedAccessException.java b/src/main/java/com/playus/communityservice/global/exception/UnauthorizedAccessException.java
new file mode 100644
index 0000000..f84329c
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/exception/UnauthorizedAccessException.java
@@ -0,0 +1,7 @@
+package com.playus.communityservice.global.exception;
+
+public class UnauthorizedAccessException extends RuntimeException{
+    public UnauthorizedAccessException(String entityName) {
+        super("해당 " + entityName + "에 대한 권한이 없습니다.");
+    }
+}
diff --git a/src/main/java/com/playus/communityservice/global/response/ErrorResponse.java b/src/main/java/com/playus/communityservice/global/response/ErrorResponse.java
new file mode 100644
index 0000000..3f6c9fd
--- /dev/null
+++ b/src/main/java/com/playus/communityservice/global/response/ErrorResponse.java
@@ -0,0 +1,40 @@
+package com.playus.communityservice.global.response;
+
+import lombok.Builder;
+import org.springframework.http.HttpStatus;
+
+@Builder
+public record ErrorResponse(
+        int code,
+        HttpStatus status,
+        String message
+) {
+
+    public static ErrorResponse badRequestError (String errorMessage) {
+        return createErrorResponse(HttpStatus.BAD_REQUEST, errorMessage);
+    }
+
+    public static ErrorResponse unauthorizedError (String errorMessage) {
+        return createErrorResponse(HttpStatus.UNAUTHORIZED, errorMessage);
+    }
+
+    public static ErrorResponse forbiddenError (String errorMessage) {
+        return createErrorResponse(HttpStatus.FORBIDDEN, errorMessage);
+    }
+
+    public static ErrorResponse notFoundError(String errorMessage) {
+        return createErrorResponse(HttpStatus.NOT_FOUND, errorMessage);
+    }
+
+    public static ErrorResponse internalServerError (String errorMessage) {
+        return createErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, errorMessage);
+    }
+
+    private static ErrorResponse createErrorResponse(HttpStatus errorStatus, String errorMessage) {
+        return ErrorResponse.builder()
+                .code(errorStatus.value())
+                .status(errorStatus)
+                .message(errorMessage)
+                .build();
+    }
+}
\ No newline at end of file
diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml
index 7903faf..ce9aa76 100644
--- a/src/main/resources/application-local.yaml
+++ b/src/main/resources/application-local.yaml
@@ -1,4 +1,6 @@
 spring:
+  config:
+    import: optional:file:.env[.properties]
   application:
     name: community-service
 


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 11**

<details>
<summary>🧹 Nitpick comments (6)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteRequest.java (1)</summary><blockquote>

`6-17`: **필드명과 에러 메시지 간 일관성을 유지하세요**

검증 메시지에서는 `postID`로 대문자 'ID'를 사용했지만, 실제 필드명은 `postId`로 소문자 'd'를 사용하고 있습니다. 일관성을 위해 둘 중 하나로 통일하는 것이 좋습니다.

```diff
-        @NotNull(message = "postID는 null일 수 없습니다!")
+        @NotNull(message = "postId는 null일 수 없습니다!")
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java (2)</summary><blockquote>

`13-14`: **에러 메시지 누락**

다른 필드에는 에러 메시지가 있지만 `image` 필드에는 없습니다. 일관성을 위해 에러 메시지를 추가하는 것이 좋습니다.

```diff
-        @Size(max = 255)
+        @Size(max = 255, message = "이미지 경로는 255자를 초과할 수 없습니다!")
```

---

`22-28`: **코드 스타일 개선**

메서드 매개변수 목록에서 `image` 다음에 불필요한 공백이 있습니다. 일관된 코드 스타일을 위해 제거하는 것이 좋습니다.

```diff
-    public static PostCreateRequest of(String title, String image , String message) {
+    public static PostCreateRequest of(String title, String image, String message) {
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateRequest.java (1)</summary><blockquote>

`18-19`: **image 필드에 대한 유효성 검증 메시지 누락**

다른 필드들과 달리 `image` 필드에는 validation 메시지가 설정되어 있지 않습니다. 일관성 있는 사용자 경험을 위해 적절한 메시지를 추가하는 것이 좋겠습니다.


```diff
-        @Size(max = 255)
+        @Size(max = 255, message = "이미지 경로는 255자 이내로 작성해 주세요!")
         String image,
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (1)</summary><blockquote>

`57-87`: **HTTP 메서드 선택에 대한 고려**

게시글 삭제 API에 `PATCH` 메서드를 사용하고 있지만, 리소스 삭제 작업에는 일반적으로 `DELETE` 메서드가 더 적합합니다. RESTful API 설계 원칙을 따라 `DELETE` 메서드를 사용하는 것을 고려해 보세요.

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/controller/PostController.java (1)</summary><blockquote>

`27-31`: **HTTP 메서드와 응답 형식 개선**

1. 삭제 작업에는 일반적으로 `DELETE` 메서드가 더 적합합니다. `PATCH` 대신 `DELETE`를 사용하는 것이 RESTful API 설계 원칙에 부합합니다.
   
2. 빈 JSON 객체 반환을 하드코딩된 문자열로 처리하는 대신 다음과 같이 개선할 수 있습니다:


```diff
-    @PatchMapping
+    @DeleteMapping
     public ResponseEntity<String> deletePost(@RequestBody @Valid PostDeleteRequest request) {
         postService.deletePost(request);
-        return ResponseEntity.ok("{}"); // 명세서에 맞게 빈 JSON 반환
+        return ResponseEntity.ok(new HashMap<>()); // 빈 객체 반환
     }
```

필요한 import 추가:
```java
import java.util.HashMap;
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between a919288b1d0b659d91276d800a1adb15962fc650 and 31ea40cda9e8676d68c2fe446a7ecd9a43e775bc.

</details>

<details>
<summary>📒 Files selected for processing (8)</summary>

* `src/main/java/com/playus/communityservice/domain/post/controller/PostController.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteRequest.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateRequest.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/repository/write/PostImageRepository.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/service/PostService.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java` (1 hunks)

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java (1)</summary>

`3-10`: **코드가 깔끔하고 잘 구성되어 있습니다!**

Java 레코드를 사용하여 DTO를 구현하고, 정적 팩토리 메서드를 제공하는 방식이 좋습니다. 응답 객체의 구조가 간결하고 명확합니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/repository/write/PostImageRepository.java (1)</summary>

`6-7`: **JPA 표준 패턴을 잘 따르고 있습니다!**

Spring Data JPA를 활용한 기본 리포지토리 인터페이스가 잘 정의되어 있습니다. 필요한 기본 CRUD 작업을 제공받을 수 있습니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateRequest.java (3)</summary>

`11-16`: **필드 유효성 검증 값의 일관성 검토**

`title` 필드의 최대 길이가 225자로 설정되어 있는데, 일반적으로 사용되는 255자가 아닌 이유가 있는지 확인해 주세요. 데이터베이스 컬럼 설정과 일치하는지 검토가 필요합니다.

---

`21-23`: **필드 이름의 일관성 검토**

`PostCreateRequest`에서는 이 필드가 `message`로 명명되어 있는데, 여기서는 `content`로 사용되고 있습니다. 일관된 명명 규칙을 사용하는 것이 코드 유지보수와 이해도를 높이는 데 도움이 됩니다.

---

`26-33`: **정적 팩토리 메서드 사용 패턴 승인**

정적 팩토리 메서드 `of`를 사용하여 객체 생성을 추상화한 방식이 좋습니다. 이는 가독성과 사용성을 높이는 좋은 패턴입니다.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-05-12T05:33:55Z
user: login: han16935
body: 고생하셧습니다~ pr 제목을 구체적으로 어떤 API를 구현했는지 작성해주시는 것도 괜찮을 거 같아요! 테스트는 어떻게 진행하셧나요? 아 그리고 rabbit이 댓글 달아준 건 전부 답변해 주시고 대략 이해햇습니다~ 이렇게 납득한 거 같은 답변이 날아오면 resolve 해 주세요! 
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:05:40Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>♻️ Duplicate comments (5)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (2)</summary><blockquote>

`50-51`: **응답 형식의 일관성 개선 필요**

"status" 필드의 값이 소문자 "ok"로 되어 있습니다. RESTful API 관례에 따라 상태 값은 대문자로 표기하는 것이 좋습니다.


```diff
-                                      "status": "ok"
+                                      "status": "OK"
```

---

`18-90`: **updatePost 메서드 명세 누락**

인터페이스에 `updatePost` 메서드에 대한 API 명세가 누락되어 있습니다. 컨트롤러 구현체에는 해당 메서드가 있으나 인터페이스 명세에 포함되어 있지 않습니다. API 문서화의 완전성을 위해 추가가 필요합니다.


다음과 같이 updatePost에 대한 API 명세를 추가해 주세요:

```java
@Tag(name = "Post", description = "게시글 수정 API")
@Operation(
        summary = "게시글 수정",
        description = "작성자가 게시글을 수정합니다.",
        requestBody = @RequestBody(
                required = true,
                content = @Content(
                        mediaType = APPLICATION_JSON_VALUE,
                        examples = @ExampleObject(
                                name = "게시글 수정 요청 예시",
                                value = """
                                {
                                  "postId": 1,
                                  "title": "수정된 제목입니다",
                                  "image": "1",
                                  "content": "수정된 내용입니다"
                                }
                                """
                        )
                )
        )
)
@ApiResponses(value = {
        @ApiResponse(
                responseCode = "200", description = "수정 성공",
                content = @Content(
                        mediaType = APPLICATION_JSON_VALUE,
                        examples = @ExampleObject(
                                name = "수정 응답 예시",
                                value = """
                                {
                                  "status": "OK"
                                }
                                """
                        )
                )
        )
})
ResponseEntity<PostUpdateResponse> updatePost(PostUpdateRequest request);
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/service/PostService.java (3)</summary><blockquote>

`29-30`: **하드코딩된 값 개선 필요**

작성자 ID와 태그가 하드코딩되어 있습니다. 이는 테스트 또는 개발 단계에서는 허용될 수 있지만, 프로덕션 코드에서는 다음과 같이 개선하는 것이 좋습니다:

1. 작성자 ID는 인증 시스템에서 가져오도록 구현
2. 태그는 클라이언트로부터 받거나, 더 유연한 기본값 설정 방식 도입


추후 인증 시스템과 연동 시 SecurityContext나 세션에서 사용자 정보를 가져오는 방식으로 변경하세요.

---

`84-89`: _🛠️ Refactor suggestion_

**하드코딩된 태그와 isSecret 값**

게시글 수정 로직에서 태그와 isSecret 값이 하드코딩되어 있습니다. 기존 게시글의 값을 유지하거나 요청에서 받은 값을 사용하는 것이 좋습니다.


다음과 같이 개선하세요:

```diff
-        post.updateAll(
-                request.title(),
-                request.content(),
-                Tag.LG_TWINS, // 임시로 태그는 고정 처리
-                false         // isSecret도 false 고정 처리
-        );
+        // 요청에 태그와 isSecret 값이 없으면 기존 값 유지
+        Tag tag = (request.tag() != null) ? request.tag() : post.getTag();
+        Boolean isSecret = (request.isSecret() != null) ? request.isSecret() : post.isSecret();
+        
+        post.updateAll(
+                request.title(),
+                request.content(),
+                tag,
+                isSecret
+        );
```

이 개선을 위해서는 DTO도 함께 수정이 필요합니다.

---

`71-92`: _🛠️ Refactor suggestion_

**게시글 수정 로직에 이미지 처리 누락**

게시글 수정 로직에는 게시글 생성과 달리 이미지 처리 로직이 구현되어 있지 않습니다. 일관성을 위해 이미지 처리 로직을 추가하는 것이 좋습니다.


다음과 같이 이미지 처리 로직을 추가하세요:

```diff
         post.updateAll(
                 request.title(),
                 request.content(),
                 Tag.LG_TWINS, // 임시로 태그는 고정 처리
                 false         // isSecret도 false 고정 처리
         );
+
+        // image 필드가 있으면 PostImage 업데이트 또는 생성
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("파일 ID가 " + fileId + "인 파일을 찾을 수 없습니다."));
+                
+                // 기존 이미지가 있으면 삭제하고 새로운 이미지 연결
+                postImageRepository.deleteByPostId(post.getId());
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("이미지 필드는 유효한 숫자 형식(파일 ID)이어야 합니다.");
+            }
+        }
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (2)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/CommunityServiceApplication.java (1)</summary><blockquote>

`7-10`: **Redis 자동 구성 제외 이유에 대한 설명이 필요합니다.**

`@SpringBootApplication` 어노테이션에서 Redis 관련 자동 구성을 제외하는 변경이 있었습니다. 이 변경의 이유를 코드 주석으로 추가하는 것이 좋겠습니다. 커뮤니티 게시글 API를 구현하는 과정에서 Redis가 필요하지 않은 것인지, 아니면 다른 이유가 있는지 명확하게 설명해주세요.

추가로, 이 변경이 다른 기능에 영향을 미치지 않는지 확인해 보세요. 만약 다른 부분에서 Redis를 사용하고 있다면, 이 설정으로 인해 의도하지 않은 문제가 발생할 수 있습니다.

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (1)</summary><blockquote>

`84-85`: **응답 형식의 일관성 유지 필요**

삭제 API의 응답이 빈 객체(`{}`)로 되어 있습니다. 생성 API와 동일하게 상태 정보를 포함하는 형식으로 통일하는 것이 좋습니다.


```diff
-                                    value = "{}"
+                                    value = """
+                                    {
+                                      "status": "OK"
+                                    }
+                                    """
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Lite**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 31ea40cda9e8676d68c2fe446a7ecd9a43e775bc and 3c87a2fde1c61f9fa15ec560836a06ce8e626716.

</details>

<details>
<summary>📒 Files selected for processing (6)</summary>

* `src/main/java/com/playus/communityservice/CommunityServiceApplication.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/controller/PostController.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/service/PostService.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java` (1 hunks)
* `src/main/resources/application-local.yaml` (1 hunks)

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* src/main/resources/application-local.yaml

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
* src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (2)</summary>

`20-57`: **API 스펙 문서화가 잘 되어 있습니다.**

Swagger 어노테이션을 사용하여 게시글 생성 API를 명확하게 문서화했습니다. 요청 본문과 응답 예시를 포함하여 API 이해도를 높였습니다.

---

`58-89`: **게시글 삭제 API 정의는 잘 구현되었습니다.**

삭제 API에 대한 명세가 잘 정의되어 있습니다. 요청과 응답 예시가 명확합니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/service/PostService.java (3)</summary>

`18-25`: **서비스 구조 및 의존성 주입이 잘 설계되었습니다.**

`@RequiredArgsConstructor`를 사용한 생성자 주입 방식과 필요한 리포지토리들의 의존성이 적절히 정의되어 있습니다.

---

`26-53`: **게시글 생성 로직이 잘 구현되었습니다.**

트랜잭션 처리와 예외 처리 방식이 적절합니다. 이미지 처리 로직이 별도로 분리되어 예외 상황에 대한 처리가 명확합니다.

---

`55-69`: **게시글 삭제 로직이 잘 구현되었습니다.**

게시글 존재 여부 확인, 작성자 검증, 활성화 상태 검증 등 필요한 검증 절차가 모두 포함되어 있습니다.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-05-12T07:07:28Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:08:32Z
user: login: han16935
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:08:55Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T07:09:03Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:10:14Z
user: login: han16935
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:12:12Z
user: login: han16935
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:13:03Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:15:54Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:18:17Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:18:56Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:20:07Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:20:57Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T07:21:32Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:21:56Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-12T07:22:19Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:22:54Z
user: login: han16935
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:32:03Z
user: login: han16935
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:40:23Z
user: login: han16935
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T07:42:29Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T01:24:04Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-14T01:24:38Z
user: login: yechan-kim
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-14T04:57:25Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-14T04:57:30Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T01:58:15Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T01:59:10Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T01:59:38Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 18**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/document/PostDocument.java (1)</summary><blockquote>

`44-53`: _⚠️ Potential issue_

**빌더에 새 필드 추가 필요**

`Builder` 생성자에 새로 추가된 `jwpDate` 필드가 포함되어 있지 않습니다. 이로 인해 빌더 패턴을 사용할 때 해당 필드를 설정할 수 없게 됩니다.

```diff
@Builder
- private PostDocument(Long id, String title, String description, TeamTag tag, Long writerId, boolean activated, boolean isSecret) {
+ private PostDocument(Long id, String title, String description, TeamTag tag, Long writerId, boolean activated, boolean isSecret, LocalDate jwpDate) {
    this.id = id;
    this.title = title;
    this.description = description;
    this.tag = tag;
    this.writerId = writerId;
    this.activated = activated;
    this.isSecret = isSecret;
+    this.jwpDate = jwpDate;
}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>♻️ Duplicate comments (1)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/service/PostService.java (1)</summary><blockquote>

`19-21`: **@Transactional 어노테이션 위치 개선**

현재 각 메서드에 개별적으로 @Transactional 어노테이션이 적용되어 있습니다. 모든 메서드가 트랜잭션을 필요로 하므로 클래스 수준에 어노테이션을 적용하는 것이 더 깔끔합니다.



```diff
@Service
@RequiredArgsConstructor
+@Transactional
public class PostService {
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (13)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/global/config/security/CorsConfig.java (1)</summary><blockquote>

`11-34`: **CORS 설정이 적절히 구현되었습니다만 환경별 설정을 고려하세요**

CORS 설정이 잘 구현되었습니다. 현재는 http://localhost:3000만 허용하고 있어 개발 환경에서는 적합합니다.

다만, 프로덕션과 같은 다른 환경에서 사용할 때 문제가 발생할 수 있습니다. 아래와 같이 application.properties/yml 파일에서 설정을 읽어오도록 변경하는 것을 고려해보세요:

```diff
-        configuration.setAllowedOrigins(List.of(
-                "http://localhost:3000"
-        ));
+        configuration.setAllowedOrigins(Arrays.asList(
+                environment.getProperty("cors.allowed-origins", "http://localhost:3000").split(",")
+        ));
```

이를 위해 Environment 빈을 주입받아야 합니다:
```java
@Autowired
private Environment environment;
```

application.yml 예시:
```yaml
cors:
  allowed-origins: http://localhost:3000,https://your-production-domain.com
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java (1)</summary><blockquote>

`16-16`: **불필요한 세미콜론 제거 필요**

enum 상수 목록의 마지막에 불필요한 세미콜론(`,;`)이 있습니다. 이는 제거되어야 합니다.

```diff
- KT_WIZ("KT 위즈"),;
+ KT_WIZ("KT 위즈");
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/document/PostDocument.java (2)</summary><blockquote>

`40-41`: **`jwpDate` 필드의 목적 명확화 필요**

`jwpDate`라는 필드명은 그 목적과 의미가 명확하지 않습니다. 더 설명적인 이름(예: `publishDate`, `creationDate` 등)을 사용하거나, 주석을 추가하여 필드의 목적을 명확히 하는 것이 좋습니다.

```diff
- @Field(name = "jwp_date")
- private LocalDate jwpDate;
+ @Field(name = "publish_date")
+ private LocalDate publishDate; // 게시물 발행 날짜
```

---

`55-65`: **팩토리 메서드에 새 필드 추가 필요**

`createForOnlyTest` 팩토리 메서드에도 새로 추가된 `jwpDate` 파라미터가 포함되어 있지 않습니다. 테스트 시 해당 필드에 대한 일관성을 유지하기 위해 추가하는 것이 좋습니다.

```diff
- public static PostDocument createForOnlyTest(Long id, Long writerId, String title, String description, TeamTag tag) {
+ public static PostDocument createForOnlyTest(Long id, Long writerId, String title, String description, TeamTag tag, LocalDate jwpDate) {
    return PostDocument.builder()
            .id(id)
            .writerId(writerId)
            .title(title)
            .description(description)
            .tag(tag)
            .activated(true)
            .isSecret(false)
+            .jwpDate(jwpDate)
            .build();
}
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java (2)</summary><blockquote>

`24-25`: **getUsername 메서드의 명확한 목적 확인**

getUsername() 메서드는 userId를 문자열로 변환하여 반환하고 있는데, 이는 getId() 메서드와 중복된 기능처럼 보일 수 있습니다. Spring Security에서는 getUsername()이 사용자의 고유 식별자를 반환하도록 설계되어 있으므로 현재 구현은 적절하지만, 코드 가독성을 위해 주석을 추가하면 좋을 것 같습니다.

---

`39-41`: **getId() 메서드의 중복 여부 검토**

getId() 메서드는 Lombok의 @Getter 어노테이션에 의해 이미 생성되었을 가능성이 높습니다. 명시적으로 구현하는 것이 특별한 목적이 있는지 확인해 주세요. 일반적인 경우라면 명시적인 구현은 제거해도 괜찮습니다.


```diff
-    public Long getId() {
-        return userId;
-    }
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/global/config/security/SecurityConfig.java (1)</summary><blockquote>

`28-37`: **화이트리스트 관리 방식 개선 제안**

현재 getWhiteList() 메서드는 문자열 배열을 직접 반환하고 있습니다. 이 방식은 항목이 추가될 때마다 코드를 수정해야 하므로 유지보수성이 낮을 수 있습니다. 설정 파일이나 상수 클래스로 분리하거나, List나 Set 같은 컬렉션을 사용하여 더 유연하게 관리하는 것이 좋습니다.


```diff
-    private String [] getWhiteList() {
-        return new String[] {
-                "/swagger",
-                "/swagger-ui.html",
-                "/swagger-ui/**",
-                "/api-docs",
-                "/api-docs/**",
-                "/v3/api-docs/**",
-        };
-    }
+    private List<String> getWhiteList() {
+        return List.of(
+                "/swagger",
+                "/swagger-ui.html",
+                "/swagger-ui/**",
+                "/api-docs",
+                "/api-docs/**",
+                "/v3/api-docs/**"
+        );
+    }
```

이 변경사항을 적용하려면 다음 import를 추가해야 합니다:
```java
import java.util.List;
```

또한 `requestMatchers(getWhiteList())` 호출 부분도 수정해야 합니다:
```diff
- .requestMatchers(getWhiteList()).permitAll()
+ .requestMatchers(getWhiteList().toArray(new String[0])).permitAll()
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/entity/Post.java (3)</summary><blockquote>

`30-31`: **jwpDate 필드의 목적과 명명 검토**

새로 추가된 jwpDate 필드의 이름이 다소 모호합니다. 필드 이름은 그 용도나 의미를 명확히 표현하는 것이 좋습니다. 예를 들어, 'postDate', 'publishDate', 'eventDate' 등 필드의 실제 목적에 맞는 이름으로 변경하는 것을 고려해 보세요. 또한, 필드에 대한 JavaDoc 주석을 추가하여 해당 필드의 목적을 설명하면 코드 이해도를 높일 수 있습니다.

---

`66-72`: **updateAll 메서드 설계 검토**

updateAll 메서드는 여러 필드를 한 번에 업데이트하는데, 이는 모든 필드를 항상 함께 수정해야 한다는 가정을 내포합니다. 실제 사용 사례에 따라 일부 필드만 선택적으로 업데이트할 수 있는 별도의 메서드(예: updateTitle, updateDescription 등)가 필요할 수 있습니다. 또는 빌더 패턴과 유사한 방식으로 선택적 업데이트를 지원하는 방법도 고려해 볼 수 있습니다.

---

`27-28`: **TeamTag enum 값 검증 고려**

TeamTag enum을 사용할 때 값이 null인 경우나 유효하지 않은 값이 전달될 가능성이 있습니다. Entity 레벨에서 이러한 상황을 처리하는 검증 로직이나 null 체크를 추가하는 것이 좋습니다. 또한, JPA에서 @Enumerated(EnumType.STRING)를 사용할 때는 enum 값이 변경되면 데이터베이스의 기존 데이터와 호환성 문제가 발생할 수 있으므로, enum 상수의 이름을 변경하지 않도록 주의해야 합니다.

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/controller/PostController.java (2)</summary><blockquote>

`31-33`: **위치 헤더 URI 형식 개선이 필요합니다.**

생성된 게시글을 조회할 수 있는 URI를 구성할 때 tag 정보가 포함되어 있지 않습니다. 완전한 리소스 경로를 제공하려면 tag 정보도 포함하는 것이 좋을 것입니다.

다음과 같이 수정하는 것을 고려해보세요:

```diff
-        URI location = URI.create("/post/" + response.postId());
+        URI location = URI.create("/post/" + tag + "/" + response.postId());
```

---

`44-49`: **API 디자인 일관성 검토**

다른 엔드포인트(create, update)는 경로 변수로 `tag`를 사용하지만, delete 엔드포인트는 이를 사용하지 않습니다. 게시글 도메인의 일관성을 위해 delete 메서드도 동일한 패턴을 따르는 것을 고려해보세요.

API 일관성을 위해 다음과 같은 변경을 고려해보세요:

```diff
-@DeleteMapping
+@DeleteMapping("/{tag}")
 public ResponseEntity<PostDeleteResponse> delete(@Valid @RequestBody PostDeleteRequest request,
+                                                @PathVariable TeamTag tag,
                                                 @AuthenticationPrincipal JwtUser user) {
-    PostDeleteResponse response = postService.deletePost(request, user);
+    PostDeleteResponse response = postService.deletePost(request, user, tag);
     return ResponseEntity.ok(response);
 }
```

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (1)</summary><blockquote>

`101-101`: **메서드 시그니처와 구현 불일치 고려**

컨트롤러에서 `delete` 메서드에 `TeamTag`를 추가하는 것을 고려한다면, 이 인터페이스 메서드도 그에 맞게 업데이트해야 합니다.

컨트롤러 일관성을 위해 다음과 같은 변경을 고려하세요:

```diff
-    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request);
+    ResponseEntity<PostDeleteResponse> deletePost(TeamTag tag, PostDeleteRequest request);
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Lite**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 3c87a2fde1c61f9fa15ec560836a06ce8e626716 and 627cbfa285255ec38a2fb6430daa55c7670cbe06.

</details>

<details>
<summary>📒 Files selected for processing (24)</summary>

* `build.gradle` (2 hunks)
* `src/main/java/com/playus/communityservice/CommunityServiceApplication.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/controller/PostController.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/document/PostDocument.java` (4 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateRequest.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/entity/Post.java` (3 hunks)
* `src/main/java/com/playus/communityservice/domain/post/enums/Tag.java` (0 hunks)
* `src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/service/PostService.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/config/jwt/JwtUtil.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/config/security/CorsConfig.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/config/security/SecurityConfig.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/exception/EntityNotFoundException.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/exception/UnauthorizedAccessException.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/response/ErrorResponse.java` (1 hunks)
* `src/main/resources/application-local.yaml` (1 hunks)

</details>

<details>
<summary>💤 Files with no reviewable changes (1)</summary>

* src/main/java/com/playus/communityservice/domain/post/enums/Tag.java

</details>

<details>
<summary>✅ Files skipped from review due to trivial changes (1)</summary>

* src/main/java/com/playus/communityservice/global/exception/UnauthorizedAccessException.java

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (3)</summary>

* src/main/resources/application-local.yaml
* src/main/java/com/playus/communityservice/CommunityServiceApplication.java
* src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateRequest.java

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (1)</summary>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (1)</summary>

```
Learnt from: gachaemin
PR: KEA-ChunSam/PlayUs-community-service#23
File: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java:89-89
Timestamp: 2025-05-14T01:24:34.940Z
Learning: PlayUs 프로젝트에서는 모든 API 응답에 표준화된 응답 DTO 파일을 적용하여 반환 타입을 통일할 예정입니다. 이는 일관된 API 응답 구조를 제공하기 위한 설계 결정입니다.
```

</details>

</details><details>
<summary>🧬 Code Graph Analysis (4)</summary>

<details>
<summary>src/main/java/com/playus/communityservice/global/config/security/CorsConfig.java (1)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/global/config/security/SecurityConfig.java (1)</summary>

* `Configuration` (20-59)

</details>

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/global/config/security/SecurityConfig.java (1)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/global/config/security/CorsConfig.java (1)</summary>

* `Configuration` (11-35)

</details>

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/service/PostService.java (2)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/global/exception/EntityNotFoundException.java (1)</summary>

* `EntityNotFoundException` (3-7)

</details>
<details>
<summary>src/main/java/com/playus/communityservice/global/exception/UnauthorizedAccessException.java (1)</summary>

* `UnauthorizedAccessException` (3-7)

</details>

</blockquote></details>
<details>
<summary>src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java (1)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java (1)</summary>

* `Slf4j` (19-57)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (11)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/global/exception/EntityNotFoundException.java (1)</summary>

`3-6`: **잘 설계된 예외 클래스입니다**

커스텀 예외 클래스가 잘 설계되었습니다. 엔티티를 찾을 수 없을 때 이 예외가 발생하고, 메시지를 한국어로 적절하게 구성합니다.

하나의 제안으로, 추가 컨텍스트를 제공하기 위해 원인을 인수로 받는 다른 생성자를 추가하는 것을 고려해 볼 수 있습니다:
```java
public EntityNotFoundException(String entityName, Throwable cause) {
    super(entityName + "을(를) 찾을 수 없습니다.", cause);
}
```

</details>
<details>
<summary>build.gradle (2)</summary>

`34-36`: **적절한 종속성 추가 - 웹소켓 및 보안**

Spring Boot WebSocket 및 Security 스타터, 그리고 Apache Commons Lang3 라이브러리 추가가 잘 이루어졌습니다. 이는 커뮤니티 서비스에서 실시간 통신 및 보안 기능을 지원하는 데 필요한 종속성입니다.

---

`73-76`: **JWT 종속성 추가가 적절합니다**

JWT 관련 종속성(`jjwt-api`, `jjwt-impl`, `jjwt-jackson`)이 적절하게 추가되었습니다. 이는 토큰 기반 인증을 구현하는 데 필요한 적절한 선택입니다.

각 라이브러리의 역할이 명확하게 구분되어 있습니다:
- `jjwt-api`: API 정의
- `jjwt-impl`: 실제 구현체 (런타임에만 필요)
- `jjwt-jackson`: JSON 직렬화/역직렬화 (런타임에만 필요)

</details>
<details>
<summary>src/main/java/com/playus/communityservice/global/config/security/SecurityConfig.java (1)</summary>

`46-49`: **인증 규칙 검토 필요**

현재 설정은 화이트리스트에 있는 경로를 제외한 모든 요청에 인증이 필요합니다. API의 일부 엔드포인트는 인증 없이 공개적으로 사용 가능해야 할 수도 있습니다(예: 공개 게시물 조회). 필요에 따라 추가적인 인증 예외 규칙을 고려해 보세요.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/global/config/jwt/JwtUtil.java (1)</summary>

`1-84`: **JWT 유틸리티 구현이 잘 되어 있습니다.**

전반적으로 JWT 토큰 생성, 검증, 파싱 기능이 잘 구현되어 있습니다. 만료 시간 관리, 클레임 설정과 추출, 서명 검증 등 필요한 기능이 모두 포함되어 있습니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/global/response/ErrorResponse.java (1)</summary>

`1-40`: **에러 응답 구조와 팩토리 메서드가 잘 설계되어 있습니다.**

ErrorResponse 레코드는 HTTP 오류에 대한 일관된 응답 형식을 제공하며, 다양한 상태 코드에 대한 팩토리 메서드를 통해 코드 재사용성을 높였습니다. 에러 처리 표준화에 좋은 접근법입니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java (1)</summary>

`1-35`: **게시글 생성 요청 DTO가 잘 구현되어 있습니다.**

유효성 검증 조건(min, max)과 에러 메시지가 일치하며, 필드별 적절한 제약 조건이 설정되어 있습니다. 이전 리뷰에서 제기된 검증 조건과 메시지 간 불일치 문제도 해결되었습니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/service/PostService.java (2)</summary>

`25-31`: **createPost 메서드 구현이 적절합니다.**

사용자 인증 정보와 요청 데이터를 활용하여 게시글을 생성하는 로직이 잘 구현되어 있습니다. 팀태그를 매개변수로 받아 유연한 구조를 가지고 있습니다.

---

`46-57`: **deletePost 메서드 구현이 적절합니다.**

게시글 존재 여부 확인, 작성자 권한 검증, 논리적 삭제 처리가 적절히 구현되어 있습니다. 커스텀 예외를 활용하여 명확한 오류 메시지를 제공하는 것도 좋은 접근법입니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/controller/PostController.java (1)</summary>

`27-34`: **생성 API의 HTTP 상태 코드가 명세와 일치하지 않습니다.**

컨트롤러는 생성 요청에 대해 201 Created 상태 코드를 반환하지만, `PostControllerSpecification` 인터페이스에서는 200 OK로 명세되어 있습니다. 이는 일관성 측면에서 수정이 필요합니다.

PostControllerSpecification 인터페이스의 응답 코드도 201로 변경하는 것을 검토해주세요.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (1)</summary>

`55-57`: **응답 형식 표준화 적용**

이전 학습 내용에 따르면, PlayUs 프로젝트에서는 모든 API 응답에 표준화된 응답 DTO 형식을 적용할 예정입니다. `PostCreateResponse`의 형식이 다른 응답(PostUpdateResponse, PostDeleteResponse)과 일치하는지 확인해주세요.

`success` 필드를 모든 응답 형식에 일관되게 적용하는 것을 고려해보세요.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-05-15T02:17:51Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T02:28:28Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:28:37Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T02:28:54Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:28:55Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T02:29:14Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:29:23Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T02:29:39Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:30:41Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T02:31:00Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:31:47Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T02:32:07Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:32:23Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T02:32:42Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T03:01:34Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T03:01:53Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>♻️ Duplicate comments (1)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (1)</summary><blockquote>

`119-121`: _⚠️ Potential issue_

**JSON 예시에 쉼표가 누락되었습니다.**

게시글 수정 요청 예시의 JSON에서 `content`와 `postId` 필드 사이에 쉼표가 누락되어 있습니다. 이는 클라이언트에서 파싱 오류를 발생시킬 수 있습니다.

```diff
{
  "title": "오늘 경기 재밌었어요!",
  "image": "2",
-  "content": "긴장하면서 시청했네요."
+  "content": "긴장하면서 시청했네요.",
  "postId": 1,
  "jwpDate" : "2025-05-01"
}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Lite**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 627cbfa285255ec38a2fb6430daa55c7670cbe06 and b11a9918b049d955cc2c58b8054bf2ae211b9414.

</details>

<details>
<summary>📒 Files selected for processing (7)</summary>

* `src/main/java/com/playus/communityservice/domain/post/controller/PostController.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/service/PostService.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (4)</summary>

* src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java
* src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java
* src/main/java/com/playus/communityservice/domain/post/service/PostService.java
* src/main/java/com/playus/communityservice/domain/post/controller/PostController.java

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧠 Learnings (1)</summary>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (1)</summary>

```
Learnt from: gachaemin
PR: KEA-ChunSam/PlayUs-community-service#23
File: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java:89-89
Timestamp: 2025-05-14T01:24:34.940Z
Learning: PlayUs 프로젝트에서는 모든 API 응답에 표준화된 응답 DTO 파일을 적용하여 반환 타입을 통일할 예정입니다. 이는 일관된 API 응답 구조를 제공하기 위한 설계 결정입니다.
```

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java (1)</summary>

`1-17`: **코드가 깔끔하고 잘 구현되었습니다!**

DTO 클래스가 명확하게 정의되어 있으며, 팩토리 메서드도 파라미터를 올바르게 사용하고 있습니다. 이전 버전에서 지적되었던 오타와 미사용 파라미터 문제가 모두 수정되었습니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java (1)</summary>

`1-16`: **코드가 깔끔하고 잘 구현되었습니다!**

DTO 클래스가 명확하게 정의되어 있으며, 팩토리 메서드도 파라미터를 올바르게 사용하고 있습니다. 이전 버전에서 지적되었던 미사용 파라미터 문제가 수정되었습니다.

</details>
<details>
<summary>src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java (3)</summary>

`24-65`: **API 명세가 잘 작성되었습니다.**

게시글 생성 API에 대한 명세가 명확하게 정의되어 있으며, 요청 및 응답 예시도 적절하게 제공되어 있습니다. API 응답 코드도 REST 원칙에 맞게 201 Created로 지정되어 있습니다.

추가적으로, 학습한 바에 따르면 PlayUs 프로젝트에서는 모든 API 응답에 표준화된 응답 DTO를 적용한다고 했는데, 이 부분이 잘 반영되어 있습니다.

---

`67-103`: **API 명세가 잘 작성되었습니다.**

게시글 삭제 API에 대한 명세가 명확하게 정의되어 있으며, 요청 예시도 적절하게 제공되어 있습니다. success 필드 타입 표기 외에는 잘 구현되어 있습니다.

---

`105-145`: **API 명세가 잘 작성되었습니다.**

게시글 수정 API에 대한 명세가 명확하게 정의되어 있으며, JSON 쉼표 누락과 success 필드 타입 표기 외에는 잘 구현되어 있습니다.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-05-15T07:15:39Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T07:17:48Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T07:17:54Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:18:09Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-15T07:18:12Z
user: login: Minminminwoo
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T09:26:53Z
user: login: Minminminwoo
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T09:28:54Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T10:00:51Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T10:03:59Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:09:53Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:09:59Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:10:04Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:10:11Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:10:19Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:10:24Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:10:34Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:10:49Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:11:04Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:11:21Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:11:23Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:11:35Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:11:56Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:11:57Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:11:59Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:12:15Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:12:16Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:12:24Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:12:44Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:12:56Z
user: login: han16935
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:13:11Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:20:55Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:27:49Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:28:11Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:28:31Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:28:52Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:29:23Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:29:41Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:31:31Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:31:51Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:32:59Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:33:18Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:33:28Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:33:50Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:35:21Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:35:42Z
user: login: gachaemin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:37:11Z
user: login: coderabbitai[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-16T00:37:33Z
user: login: coderabbitai[bot]
state: APPROVED
author_association: NONE
submitted_at: 2025-05-16T00:47:14Z
user: login: han16935
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T00:52:14Z

Review comments:
diff_hunk: @@ -0,0 +1,29 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import jakarta.validation.constraints.*;
+import lombok.Builder;
+
+@Builder
+public record PostCreateRequest(
+
+        @NotBlank(message = "게시글 제목이 비어 있습니다!")
+        @Size(max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        String title,
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**검증 제약조건과 메시지 간 불일치가 있습니다**

에러 메시지에서 "제목의 길이를 1~225자 이내로 작성해 주세요!"라고 되어 있지만, 실제 제약조건은 최대 길이만 체크하고 있습니다. 메시지와 일치하도록 최소 길이도 추가하는 것이 좋습니다.

```diff
        @NotBlank(message = "게시글 제목이 비어 있습니다!")
-        @Size(max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        @Size(min = 1, max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        @NotBlank(message = "게시글 제목이 비어 있습니다!")
        @Size(min = 1, max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
        String title,
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 3c87a2f
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,29 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import jakarta.validation.constraints.*;
+import lombok.Builder;
+
+@Builder
+public record PostCreateRequest(
+
+        @NotBlank(message = "게시글 제목이 비어 있습니다!")
+        @Size(max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        String title,
+
+        @Size(max = 255)
+        String image,
+
+        @NotBlank(message = "본문이 비어 있습니다!")
+        @Size(max = 500, message = "본문의 길이를 1~500자 이내로 작성해 주세요!")
+        String message
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**검증 제약조건과 메시지 간 불일치가 있습니다**

에러 메시지에서 "본문의 길이를 1~500자 이내로 작성해 주세요!"라고 되어 있지만, 실제 제약조건은 최대 길이만 체크하고 있습니다. 메시지와 일치하도록 최소 길이도 추가하는 것이 좋습니다.

```diff
        @NotBlank(message = "본문이 비어 있습니다!")
-        @Size(max = 500, message = "본문의 길이를 1~500자 이내로 작성해 주세요!")
+        @Size(min = 1, max = 500, message = "본문의 길이를 1~500자 이내로 작성해 주세요!")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        @NotBlank(message = "본문이 비어 있습니다!")
        @Size(min = 1, max = 500, message = "본문의 길이를 1~500자 이내로 작성해 주세요!")
        String message
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 3c87a2f
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,88 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "ok"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<String> createPost(PostCreateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**인터페이스 명세와 구현의 불일치**

현재 `PostController` 클래스에서는 `updatePost` 메서드가 구현되어 있지만, 이 명세 인터페이스에는 해당 메서드가 정의되어 있지 않습니다. API 문서화의 완전성을 위해 `updatePost` 메서드도 이 인터페이스에 명세를 추가해야 합니다.


다음과 같이 updatePost에 대한 API 명세를 추가해 주세요:

```java
@Tag(name = "Post", description = "게시글 수정 API")
@Operation(
        summary = "게시글 수정",
        description = "작성자가 게시글을 수정합니다.",
        requestBody = @RequestBody(
                required = true,
                content = @Content(
                        mediaType = APPLICATION_JSON_VALUE,
                        examples = @ExampleObject(
                                name = "게시글 수정 요청 예시",
                                value = """
                                {
                                  "postId": 1,
                                  "title": "수정된 제목입니다",
                                  "image": "1",
                                  "content": "수정된 내용입니다"
                                }
                                """
                        )
                )
        )
)
@ApiResponses(value = {
        @ApiResponse(
                responseCode = "200", description = "수정 성공",
                content = @Content(
                        mediaType = APPLICATION_JSON_VALUE,
                        examples = @ExampleObject(
                                name = "수정 응답 예시",
                                value = """
                                {
                                  "status": "OK"
                                }
                                """
                        )
                )
        )
})
ResponseEntity<PostUpdateResponse> updatePost(PostUpdateRequest request);
```

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,88 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "ok"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**응답 형식 개선 필요**

API 응답으로 `"ok"`를 문자열로 반환하는 것은 표준 JSON 형식과 맞지 않습니다. 다음과 같이 표준 JSON 객체 형태로 변경하는 것이 좋습니다:

```diff
-                                      "ok"
+                                      "status": "OK"
```

이 변경은 컨트롤러 구현 코드와 함께 수정되어야 합니다.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
                                      "status": "OK"
                                    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,38 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.domain.post.specification.PostControllerSpecification;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController implements PostControllerSpecification {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<String> createPost(@RequestBody @Valid PostCreateRequest request) {
+        postService.createPost(request);
+        return ResponseEntity.ok("{\"ok\"}");
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**응답 형식 개선**

JSON 형식의 응답을 하드코딩된 문자열로 반환하는 것보다 객체를 반환하는 것이 더 적절합니다. ResponseEntity의 body로 객체를 사용하면 Spring이 자동으로 JSON 직렬화를 처리합니다.


예를 들어 다음과 같이 변경할 수 있습니다:

```diff
-        return ResponseEntity.ok("{\"ok\"}");
+        return ResponseEntity.ok(Map.of("status", "OK"));
```

이를 위해 다음 import를 추가해야 합니다:
```java
import java.util.Map;
```

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 3c87a2f
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,38 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.domain.post.specification.PostControllerSpecification;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController implements PostControllerSpecification {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<String> createPost(@RequestBody @Valid PostCreateRequest request) {
+        postService.createPost(request);
+        return ResponseEntity.ok("{\"ok\"}");
+    }
+
+    @PatchMapping
+    public ResponseEntity<String> deletePost(@RequestBody @Valid PostDeleteRequest request) {
+        postService.deletePost(request);
+        return ResponseEntity.ok("{}"); // 명세서에 맞게 빈 JSON 반환
+    }
+
+    @PutMapping
+    public ResponseEntity<PostUpdateResponse> updatePost(@RequestBody @Valid PostUpdateRequest request) {
+        PostUpdateResponse response = postService.updatePost(request);
+        return ResponseEntity.ok(response);
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**명세 인터페이스 구현 누락 확인**

`updatePost` 메서드가 `PostControllerSpecification` 인터페이스에 정의되어 있지 않습니다. 클래스가 인터페이스를 완전히 구현하기 위해서는 인터페이스에도 이 메서드를 추가해야 합니다.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**하드코딩된 값 개선 필요**

작성자 ID와 태그가 하드코딩되어 있습니다. 이는 테스트 또는 개발 단계에서는 허용될 수 있지만, 프로덕션 코드에서는 다음과 같이 개선하는 것이 좋습니다:

1. 작성자 ID는 인증 시스템에서 가져오도록 구현
2. 태그는 클라이언트로부터 받거나, 더 유연한 기본값 설정 방식 도입


추후 인증 시스템과 연동 시 SecurityContext나 세션에서 사용자 정보를 가져오는 방식으로 변경하세요.

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 627cbfa

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**필드 이름 불일치**

`message` 필드를 사용하고 있지만, `PostUpdateRequest`에서는 동일한 목적으로 `content` 필드를 사용합니다. DTO 간의 일관성을 유지하기 위해 같은 목적의 필드는 동일한 이름을 사용해야 합니다.


다음과 같이 `PostCreateRequest`의 필드 이름을 `content`로 통일하거나, `PostUpdateRequest`의 필드 이름을 `message`로 변경하세요.

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 3c87a2f
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**예외 처리 및 이미지 처리 논리 개선**

이미지 필드 처리 코드에 몇 가지 개선할 점이 있습니다:

1. 예외 메시지가 영어와 한글이 혼용되어 있어 일관성이 없습니다.
2. `NumberFormatException`을 잡아 `IllegalArgumentException`으로 변환하는 것은 좋은 방식이지만, 오류 메시지를 좀 더 사용자 친화적으로 만들 수 있습니다.
3. `updatePost` 메서드에는 이미지 처리 로직이 없어 비일관적입니다.


예외 메시지를 일관된 언어(한글)로 통일하고, 이미지 처리 로직을 `updatePost` 메서드에도 추가하는 것이 좋겠습니다.

```diff
-                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                        .orElseThrow(() -> new IllegalArgumentException("파일 ID가 " + fileId + "인 파일을 찾을 수 없습니다."));
```

```diff
-                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+                throw new IllegalArgumentException("이미지 필드는 유효한 숫자 형식(파일 ID)이어야 합니다.");
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        if (request.image() != null && !request.image().isBlank()) {
            try {
                Long fileId = Long.parseLong(request.image());
                File file = fileRepository.findById(fileId)
                        .orElseThrow(() -> new IllegalArgumentException("파일 ID가 " + fileId + "인 파일을 찾을 수 없습니다."));
                PostImage postImage = PostImage.create(post, file);
                postImageRepository.save(postImage);
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("이미지 필드는 유효한 숫자 형식(파일 ID)이어야 합니다.");
            }
        }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-12T05:33:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글입니다.");
+        }
+
+        post.delete();
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**삭제 로직과 예외 처리**

삭제 로직에서 다음 사항을 개선할 수 있습니다:

1. 예외 메시지의 일관성: 일부는 영어, 일부는 한글로 되어 있습니다.
2. 권한 검사 부재: 현재는 게시글 작성자 확인 과정이 없습니다.


다음과 같이 개선하세요:

```diff
-                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+                .orElseThrow(() -> new IllegalArgumentException("ID가 " + request.postId() + "인 게시글을 찾을 수 없습니다."));

+        // 작성자 확인 로직 추가
+        Long currentUserId = 1L; // 향후 인증 시스템에서 가져오기
+        if (!post.getWriterId().equals(currentUserId)) {
+            throw new IllegalStateException("게시글 작성자만 삭제할 수 있습니다.");
+        }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    @Transactional
    public void deletePost(PostDeleteRequest request) {
        Post post = postRepository.findById(request.postId())
                .orElseThrow(() -> new IllegalArgumentException("ID가 " + request.postId() + "인 게시글을 찾을 수 없습니다."));

        // 작성자 확인 로직 추가
        Long currentUserId = 1L; // 향후 인증 시스템에서 가져오기
        if (!post.getWriterId().equals(currentUserId)) {
            throw new IllegalStateException("게시글 작성자만 삭제할 수 있습니다.");
        }

        if (!post.isActivated()) {
            throw new IllegalStateException("이미 삭제된 게시글입니다.");
        }

        post.delete();
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 3c87a2f
created_at: 2025-05-12T05:33:54Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글입니다.");
+        }
+
+        post.delete();
+    }
+
+    @Transactional
+    public PostUpdateResponse updatePost(PostUpdateRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글은 수정할 수 없습니다.");
+        }
+
+        post.updateAll(
+                request.title(),
+                request.content(),
+                Tag.LG_TWINS, // 임시로 태그는 고정 처리
+                false         // isSecret도 false 고정 처리
+        );
+
+        return PostUpdateResponse.ok();
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**업데이트 로직의 일관성 및 개선**

업데이트 로직에 몇 가지 개선할 점이 있습니다:

1. 예외 메시지의 일관성 유지
2. 권한 검사 부재
3. 이미지 처리 로직 누락
4. 태그와 isSecret 값이 하드코딩되어 있음


다음 개선 사항을 고려하세요:

1. 예외 메시지를 한글로 통일
2. 작성자 확인 로직 추가
3. `createPost`와 유사하게 이미지 처리 로직 추가
4. 태그와 isSecret 값을 요청에서 받거나 기존 값 유지하는 로직 추가

```diff
-                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+                .orElseThrow(() -> new IllegalArgumentException("ID가 " + request.postId() + "인 게시글을 찾을 수 없습니다."));

+        // 작성자 확인 로직 추가
+        Long currentUserId = 1L; // 향후 인증 시스템에서 가져오기
+        if (!post.getWriterId().equals(currentUserId)) {
+            throw new IllegalStateException("게시글 작성자만 수정할 수 있습니다.");
+        }
```

또한 이미지 처리 로직을 추가하고, 태그와 isSecret 값의 하드코딩을 제거하는 것이 좋겠습니다.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    @Transactional
    public PostUpdateResponse updatePost(PostUpdateRequest request) {
        Post post = postRepository.findById(request.postId())
                .orElseThrow(() -> new IllegalArgumentException("ID가 " + request.postId() + "인 게시글을 찾을 수 없습니다."));

        // 작성자 확인 로직 추가
        Long currentUserId = 1L; // 향후 인증 시스템에서 가져오기
        if (!post.getWriterId().equals(currentUserId)) {
            throw new IllegalStateException("게시글 작성자만 수정할 수 있습니다.");
        }

        if (!post.isActivated()) {
            throw new IllegalStateException("이미 삭제된 게시글은 수정할 수 없습니다.");
        }

        post.updateAll(
                request.title(),
                request.content(),
                Tag.LG_TWINS, // 임시로 태그는 고정 처리
                false         // isSecret도 false 고정 처리
        );

        return PostUpdateResponse.ok();
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-12T05:33:54Z
author_association: NONE
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: han16935
body: 게시글 생성 후 게시글의 pk를 프론트 쪽으로 넘겨주는 response가 잇으면 좋을 거 같아요~
created_at: 2025-05-12T06:55:23Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: han16935
body: 게시글 업데이트, 삭제 후 프론트 측에 성공했다는 메시지를 넘겨주는 건 어떨까요? 예를 들면 "게시글 업데이트에 성공했습니다!" "게시글 삭제 성공했습니다!" 요런 느낌으로요 보니까 community 측 API 명세서 response에 아무것도 없던데 굳이 저걸 다 지킬 필요는 없습니다! 필요, 혹은 피그마 디자인 보면서 바꾸셔도 되요!
created_at: 2025-05-12T06:57:00Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: han16935
body: try-catch 대신 `ControllerAdvice` 라는 걸 써서 예외 처리를 해 보시는 건 어떨까요? 이번 pr에선 안 보여서 혹시 이미 관련 클래스가 있다면 신경 안 쓰셔도 됩니다...!
created_at: 2025-05-12T07:01:14Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: han16935
body: Custom Exception을 쓰지 않고 `IllegalArgumentException` 통해 처리하신 이유가 잇을까요?
created_at: 2025-05-12T07:02:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,90 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "status": "ok"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<Map<String, String>> createPost(PostCreateRequest request);
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = "{}"
+                            )
+                    )
+            )
+    })
+    ResponseEntity<String> deletePost(PostDeleteRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**반환 타입 불일치**

`deletePost` 메서드는 `ResponseEntity<String>`을 반환하지만, 응답 예시는 빈 JSON 객체입니다. 메서드 시그니처와 실제 응답이 일치하도록 수정이 필요합니다.


다음과 같이 반환 타입을 Map으로 변경하거나 응답 예시를 문자열로 변경하세요:

```diff
-    ResponseEntity<String> deletePost(PostDeleteRequest request);
+    ResponseEntity<Map<String, String>> deletePost(PostDeleteRequest request);
```

또는 실제 응답 예시를 String으로 변경하세요.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    ResponseEntity<Map<String, String>> deletePost(PostDeleteRequest request);
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-12T07:07:27Z
author_association: NONE
diff_hunk: @@ -0,0 +1,94 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L;
+        Tag defaultTag = Tag.LG_TWINS;
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.content(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("파일 ID가 " + fileId + "인 파일을 찾을 수 없습니다."));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("이미지 필드는 유효한 숫자 형식(파일 ID)이어야 합니다.");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("ID가 " + request.postId() + "인 게시글을 찾을 수 없습니다."));
+
+        Long currentUserId = 1L;
+        if (!post.getWriterId().equals(currentUserId)) {
+            throw new IllegalStateException("게시글 작성자만 삭제할 수 있습니다.");
+        }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**사용자 인증 처리 개선 필요**

현재는 사용자 ID가 하드코딩되어 있습니다. 실제 프로덕션 환경에서는 인증된 사용자 정보를 가져와 비교해야 합니다.


다음과 같이 개선이 필요합니다:

---

🏁 Script executed:

```shell
#!/bin/bash
# 현재 프로젝트에서 사용자 인증 관련 코드 확인

# 인증 관련 클래스나 유틸리티 검색
echo "인증 관련 클래스 및 유틸리티 검색"
rg -l "Authentication|Security|UserDetails|Principal" --type java

# SecurityContext 사용 패턴 확인
echo "\n현재 프로젝트에서 SecurityContext 사용 패턴 확인"
rg "SecurityContextHolder" --type java -A 3 -B 1
```

Length of output: 331

---



</details>

**인증 처리 로직 추가 필요**

현재 `PostService`의 삭제 권한 검증에서 `currentUserId = 1L`로 하드코딩되어 있어 실제 인증된 사용자와 비교되지 않습니다. 프로덕션 환경에서는 반드시 Spring Security(또는 적절한 인증 모듈)를 도입해, `SecurityContextHolder` 등에서 가져온 실제 로그인 사용자 ID로 대체해야 합니다.

- 대상 파일:  
  src/main/java/com/playus/communityservice/domain/post/service/PostService.java  
- 문제 지점 (60–63행):  
  ```java
        Long currentUserId = 1L;
        if (!post.getWriterId().equals(currentUserId)) {
            throw new IllegalStateException("게시글 작성자만 삭제할 수 있습니다.");
        }
  ```

- 개선 예시:
  ```diff
  - Long currentUserId = 1L;
  + Long currentUserId = ((UserDetailsImpl) SecurityContextHolder
  +     .getContext()
  +     .getAuthentication()
  +     .getPrincipal())
  +     .getId();

    if (!post.getWriterId().equals(currentUserId)) {
        throw new IllegalStateException("게시글 작성자만 삭제할 수 있습니다.");
    }
  ```
  
  *UserDetailsImpl*은 직접 구현한 `UserDetails` 클래스이며, 필요 시 `Authentication`에서 사용자 ID를 반환하도록 커스터마이징하세요.

- 추가 작업  
  - Spring Security 의존성(pom.xml/gradle)에 추가  
  - `SecurityConfig` 작성 및 인증·인가 설정

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 627cbfa

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-12T07:07:27Z
author_association: NONE
diff_hunk: @@ -0,0 +1,29 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import jakarta.validation.constraints.*;
+import lombok.Builder;
+
+@Builder
+public record PostCreateRequest(
+
+        @NotBlank(message = "게시글 제목이 비어 있습니다!")
+        @Size(max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        String title,
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java
user: login: gachaemin
body: @coderabbitai
이해했습니다! 변경하도록 하겠습니다
created_at: 2025-05-12T07:08:32Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/CommunityServiceApplication.java
user: login: han16935
body: 여기서 Redis 관련 configuration 클래스를 exclude 하신 이유가 있을까요? 
created_at: 2025-05-12T07:08:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,29 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import jakarta.validation.constraints.*;
+import lombok.Builder;
+
+@Builder
+public record PostCreateRequest(
+
+        @NotBlank(message = "게시글 제목이 비어 있습니다!")
+        @Size(max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        String title,
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java
user: login: coderabbitai[bot]
body: @gachaemin 안녕하세요! 이해해 주셔서 감사합니다. 이미 3c87a2f 커밋에서 변경 사항이 반영된 것으로 보입니다. 코드 일관성과 명확한 검증 제약조건을 유지하는 것은 좋은 습관입니다. 👍


(\_/)
(•ᴗ•)
/ >🌟

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%EA%B0%80%20%EB%A9%94%EC%8B%9C%EC%A7%80%EC%99%80%20%EA%B2%80%EC%A6%9D%20%EC%A0%9C%EC%95%BD%EC%A1%B0%EA%B1%B4%20%EB%B6%88%EC%9D%BC%EC%B9%98%20%EB%AC%B8%EC%A0%9C%EB%A5%BC%20%EC%A0%95%ED%99%95%ED%9E%88%20%EC%A7%9A%EC%96%B4%EC%A4%AC%EC%96%B4%EC%9A%94!%20%EC%97%90%EB%9F%AC%20%EB%A9%94%EC%8B%9C%EC%A7%80%20%EC%8B%A0%EB%A2%B0%EB%8F%84%20UP%2C%20%EC%BD%94%EB%93%9C%20%ED%92%88%EC%A7%88%EB%8F%84%20UP!%20%F0%9F%9B%A0%EF%B8%8F%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94!%20%23%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2083848733)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-12T07:09:03Z
author_association: NONE
path: src/main/java/com/playus/communityservice/CommunityServiceApplication.java
user: login: gachaemin
body: community에서는 redis를 사용하지 않는걸로 알고 있고, redis관련 오류가 발생하여 exclude하였습니다! 혹시 나중에 필요하다고 하면 다시 추가하려고 합니다.
created_at: 2025-05-12T07:10:14Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: han16935
body: `@Transactional` 을 method 단이 아닌 class 단에 작성하셔도 괜찮을 거 같아요! 
created_at: 2025-05-12T07:12:12Z
author_association: CONTRIBUTOR
path: src/main/resources/application-local.yaml
user: login: han16935
body: 여기서 `config.import` 이 부분은 제가 한 번도 안 써봐서 그러는데 실례가 안 된다면 혹시 설명 부탁드려도 괜찮을까요...?
created_at: 2025-05-12T07:13:03Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: try-catch보다 controllerAdvice를 추천하시는 이유를 알 수 있을까요?
created_at: 2025-05-12T07:15:54Z
author_association: CONTRIBUTOR
path: src/main/resources/application-local.yaml
user: login: gachaemin
body: .env파일을 환경변수에 경로로 적용시켰는데 제꺼에서는 자꾸 env파일 인식을 못해서, local에 config.import를 사용해서 env파일을 인식하도록 설정했습니다!
created_at: 2025-05-12T07:18:17Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: 일단 따로 했었는데, 저도 확인해보니 class단으로 작성하는게 더 깔끔할거같네요. 변경하도록 하겠습니다!
created_at: 2025-05-12T07:18:56Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: gachaemin
body: API명세서 그대로 진행해야하는줄 알았어요..!! response를 추가하도록 할게요!
created_at: 2025-05-12T07:20:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,88 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "ok"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<String> createPost(PostCreateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
코드 작업에만 집중하여 빠트린것으로 확인됩니다! 다음 commit코드에서 변경하도록 하겠습니다.
created_at: 2025-05-12T07:20:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,88 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "ok"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<String> createPost(PostCreateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 이해합니다! 다음 커밋에서 업데이트하실 계획이신 것 감사합니다. API 명세와 실제 구현 사이의 일관성을 유지하는 것은 좋은 실천입니다. 추가 도움이 필요하시면 언제든지 말씀해주세요!

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%EA%B0%80%20%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80%20%EA%B5%AC%ED%98%84%20%EB%B6%88%EC%9D%BC%EC%B9%98%20%EB%AC%B8%EC%A0%9C%EB%A5%BC%20%EC%A0%95%ED%99%95%ED%9E%88%20%EC%A7%9A%EC%96%B4%EC%A4%AC%EC%96%B4%EC%9A%94!%20API%20%EB%AA%85%EC%84%B8%20%EB%88%84%EB%9D%BD%20%EC%97%86%EC%9D%B4%20%EC%99%84%EB%B2%BD%ED%95%9C%20%EB%AC%B8%EC%84%9C%ED%99%94%EB%A1%9C%20%EC%8B%A0%EB%A2%B0%EB%8F%84%20UP!%20%EC%BD%94%EB%93%9C%20%ED%92%88%EC%A7%88%20%EC%B1%99%EA%B8%B0%EB%A0%A4%EB%A9%B4%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94%20%F0%9F%9A%80%F0%9F%93%8B&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2083848737)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-12T07:21:32Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: @coderabbitai
이 부분은 제가 정확하게 알지 못해서, 팀원들과 이야기하고 변경하도록 하겠습니다.
created_at: 2025-05-12T07:21:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 이해합니다. 팀원들과 함께 이 부분에 대해 논의하시고 적절한 방식으로 구현하시는 것이 좋겠습니다. 필요한 도움이 있으시면 언제든지 말씀해주세요. 👍

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-12T07:22:19Z
author_association: NONE
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: 간단한 개발이 가능하다고 알아서 적용했습니다. 그런데 검색해보니 정확한 경고문이 뜨는게 아니더라구요. 다른 내용 변경하면서 이것도 따로 변경하도록 하겠습니다.
created_at: 2025-05-12T07:22:54Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: han16935
body: 아 그리고 createPost() 반환 시 200 대신 201로 반환해주세요! ResponseStatus로 하실 거면 `ResponseStatus.created().body(xxx);` 느낌으로 하면 됐을 거에요!
created_at: 2025-05-12T07:32:03Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: han16935
body: `try-catch` 문 같은 경우는 지저분하기도 하고, business logic을 처리하는 곳과 exception 을 처리하는 곳은 분리되어야 보다 관심사의 분리가 이뤄진다고 생각해요~ 많이 사용되는 곳은 예를 들면 앞서 request 객체에 있는 `@NotNull` 같은 경우에도 
따로 작성하신 규칙을 위반하면 `BindException` 이 throw 되는데, throw 될 경우에 따로 controller 등에 관련 로직을 작성할 필요 없이, advice에서 처리가 가능해요!
```
@ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public ErrorResponse bindExceptionHandler(BindException e) {
        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
        log.warn("Validation Error: {}", errorMessage);
        return ErrorResponse.badRequestError(errorMessage);
    }
``` 
created_at: 2025-05-12T07:40:23Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: han16935
body: 넵! custom exception과 표준 예외 대해서는 무조건 이쪽이 맞다! 그 정도까진 아니여서 한 번 찾아보셔도 괜찮을 거 같아요~
created_at: 2025-05-12T07:42:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,90 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "status": "ok"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<Map<String, String>> createPost(PostCreateRequest request);
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = "{}"
+                            )
+                    )
+            )
+    })
+    ResponseEntity<String> deletePost(PostDeleteRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
전체적으로 response 파일을 제작하여 모든 타입을 통일하도록 변경할 예정입니다.
created_at: 2025-05-14T01:24:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,90 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "status": "ok"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<Map<String, String>> createPost(PostCreateRequest request);
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = "{}"
+                            )
+                    )
+            )
+    })
+    ResponseEntity<String> deletePost(PostDeleteRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 표준화된 응답 DTO를 만들어 모든 API 응답 타입을 통일하는 것은 매우 좋은 접근 방식입니다. 이미 `PostUpdateResponse`와 같은 응답 DTO를 구현하셨던 것처럼, 모든 엔드포인트에 일관된 응답 구조를 적용하면 API의 일관성과 유지보수성이 크게 향상될 것입니다. 계획대로 진행하시면 좋겠습니다! 👍

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: gachaemin
PR: KEA-ChunSam/PlayUs-community-service#23
File: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java:89-89
Timestamp: 2025-05-14T01:24:34.940Z
Learning: PlayUs 프로젝트에서는 모든 API 응답에 표준화된 응답 DTO 파일을 적용하여 반환 타입을 통일할 예정입니다. 이는 일관된 API 응답 구조를 제공하기 위한 설계 결정입니다.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-14T01:24:37Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: yechan-kim
body: 작성자 ID 같은 경우에는 컨트롤러에 `@AuthenticationPrincipal`을 붙여, JWT 토큰에서 추출한 인증 객체를 통해 작성자 ID를 저장할 수 있습니다.
또한 `Tag` 같은 경우에는, 클라이언트에서 제공하는 방법으로 변경하는 것이 좋을 것 같습니다! 해당 부분은 클라이언트 파트에게 전달하도록 하겠습니다.
created_at: 2025-05-14T04:57:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: > Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

<!-- This is an auto-generated mute comment by CodeRabbit -->
created_at: 2025-05-14T04:57:30Z
author_association: NONE
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: gachaemin
body: controller 수정하면서 적용하도록 하겠습니다!
created_at: 2025-05-15T01:58:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,94 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L;
+        Tag defaultTag = Tag.LG_TWINS;
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.content(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("파일 ID가 " + fileId + "인 파일을 찾을 수 없습니다."));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("이미지 필드는 유효한 숫자 형식(파일 ID)이어야 합니다.");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("ID가 " + request.postId() + "인 게시글을 찾을 수 없습니다."));
+
+        Long currentUserId = 1L;
+        if (!post.getWriterId().equals(currentUserId)) {
+            throw new IllegalStateException("게시글 작성자만 삭제할 수 있습니다.");
+        }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: @coderabbitai
TeamTag와 연동하여 하드코딩없이 사용하도록 수정하겠습니다.
created_at: 2025-05-15T01:59:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,94 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L;
+        Tag defaultTag = Tag.LG_TWINS;
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.content(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("파일 ID가 " + fileId + "인 파일을 찾을 수 없습니다."));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("이미지 필드는 유효한 숫자 형식(파일 ID)이어야 합니다.");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("ID가 " + request.postId() + "인 게시글을 찾을 수 없습니다."));
+
+        Long currentUserId = 1L;
+        if (!post.getWriterId().equals(currentUserId)) {
+            throw new IllegalStateException("게시글 작성자만 삭제할 수 있습니다.");
+        }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: @gachaemin TeamTag 연동으로 인증 처리하는 방식으로 개선하시겠다니 좋은 접근입니다. 하드코딩된 값을 제거함으로써 보안성과 유지보수성이 크게 향상될 것입니다.



---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: gachaemin
PR: KEA-ChunSam/PlayUs-community-service#23
File: src/main/java/com/playus/communityservice/domain/post/service/PostService.java:60-63
Timestamp: 2025-05-15T01:59:35.572Z
Learning: PlayUs 프로젝트에서는 사용자 인증을 위해 TeamTag를 연동하여 사용하고, PostService와 같은 서비스 계층에서 하드코딩된 사용자 ID 대신 이 인증 메커니즘을 활용해야 합니다.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20%ED%95%98%EB%93%9C%EC%BD%94%EB%94%A9%EB%90%9C%20%EC%82%AC%EC%9A%A9%EC%9E%90%20ID%20%EB%8C%80%EC%8B%A0%20Spring%20Security%EC%9D%98%20SecurityContextHolder%EC%97%90%EC%84%9C%20%EC%8B%A4%EC%A0%9C%20%EB%A1%9C%EA%B7%B8%EC%9D%B8%20%EC%82%AC%EC%9A%A9%EC%9E%90%20ID%EB%A5%BC%20%EA%B0%80%EC%A0%B8%EC%99%80%20%EA%B6%8C%ED%95%9C%20%EA%B2%80%EC%A6%9D%ED%95%98%EC%84%B8%EC%9A%94!%20%EB%B3%B4%EC%95%88%20%EA%B0%95%ED%99%94%20%ED%95%84%EC%88%98%20%F0%9F%94%90%F0%9F%9A%80%20%23%EA%B0%9C%EB%B0%9C%ED%8C%81&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2083972053)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T01:59:38Z
author_association: NONE
diff_hunk: @@ -0,0 +1,16 @@
+package com.playus.communityservice.domain.post.dto.post_update;
+
+import lombok.Builder;
+
+@Builder
+public record PostUpdateResponse(
+        boolean success,
+        String message
+) {
+    public static PostUpdateResponse fo(boolean success, String message) {
+        return PostUpdateResponse.builder()
+                .success(true)
+                .message("게시물이 수정되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**팩토리 메서드 이름 및 로직을 수정해야 합니다**

`fo` 메서드에 문제가 있습니다:

1. 메서드 이름이 설명적이지 않습니다 - `of` 또는 `success`와 같이 더 명확한 이름을 사용하세요.
2. 매개변수를 무시하고 항상 성공 응답을 반환합니다. 이는 버그로 보입니다.

아래와 같이 수정해보세요:

```diff
-    public static PostUpdateResponse fo(boolean success, String message) {
+    public static PostUpdateResponse of(boolean success, String message) {
         return PostUpdateResponse.builder()
-                .success(true)
-                .message("게시물이 수정되었습니다.")
+                .success(success)
+                .message(message)
                 .build();
     }
```

또는 성공 응답을 위한 별도의 팩토리 메서드를 추가하는 것이 좋습니다:

```java
public static PostUpdateResponse success() {
    return PostUpdateResponse.builder()
            .success(true)
            .message("게시물이 수정되었습니다.")
            .build();
}

public static PostUpdateResponse failure(String message) {
    return PostUpdateResponse.builder()
            .success(false)
            .message(message)
            .build();
}
```

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java
around lines 10 to 15, rename the factory method from 'fo' to a more descriptive
name like 'success' or 'of'. Fix the logic so it does not ignore the input
parameters; either use the parameters to set success and message or create two
separate factory methods: one for success with a fixed success message and true
status, and another for failure that accepts a message and sets success to
false. This will make the method names clear and the behavior correct.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import lombok.Builder;
+
+@Builder
+public record PostCreateResponse(
+        Long postId,
+        String massage
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**필드명 오타 수정 필요**

`massage`는 `message`로 수정되어야 합니다. 오타가 있으면 API 응답 명세가 일관성 없게 되고 클라이언트에서 혼란을 야기할 수 있습니다.

```diff
public record PostCreateResponse(
        Long postId,
-        String massage
+        String message
) {
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
public record PostCreateResponse(
        Long postId,
        String message
) {
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
at line 8, the field name is misspelled as "massage". Rename this field to
"message" to correct the typo and ensure consistency in the API response
specification.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import lombok.Builder;
+
+@Builder
+public record PostCreateResponse(
+        Long postId,
+        String massage
+) {
+
+    public static PostCreateResponse of(Long postId, String massage) {
+        return PostCreateResponse.builder()
+                .postId(postId)
+                .massage("게시물 생성이 완료되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**팩토리 메서드의 파라미터 사용 방식 개선 필요**

현재 `of` 메서드는 `massage` 파라미터를 받고 있지만 사용하지 않고 있습니다. 대신 고정된 메시지를 사용합니다. 이는 API 사용자에게 혼란을 줄 수 있습니다.


아래 두 가지 방법 중 하나로 수정하는 것을 권장합니다:

1. 사용하지 않는 파라미터 제거:
```diff
- public static PostCreateResponse of(Long postId, String massage) {
+ public static PostCreateResponse of(Long postId) {
    return PostCreateResponse.builder()
            .postId(postId)
-            .massage("게시물 생성이 완료되었습니다.")
+            .message("게시물 생성이 완료되었습니다.")
            .build();
}
```

2. 파라미터 활용:
```diff
- public static PostCreateResponse of(Long postId, String massage) {
+ public static PostCreateResponse of(Long postId, String message) {
    return PostCreateResponse.builder()
            .postId(postId)
-            .massage("게시물 생성이 완료되었습니다.")
+            .message(message != null ? message : "게시물 생성이 완료되었습니다.")
            .build();
}
```

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
between lines 11 and 16, the factory method 'of' takes a 'massage' parameter but
does not use it, instead setting a fixed message. To fix this, either remove the
unused 'massage' parameter from the method signature if the message should
always be fixed, or modify the method to use the passed 'massage' parameter when
setting the message field, ensuring the parameter is utilized properly and
avoiding confusion for API users.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,28 @@
+package com.playus.communityservice.domain.post.enums;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public enum TeamTag {
+    DOOSAN_BEARS("두산 베어스"),
+    HANWHA_EAGLES("한화 이글스"),
+    KIA_TIGERS("KIA 타이거즈"),
+    KIWOOM_HEROES("키움 히어로즈"),
+    LG_TWINS("LG 트윈스"),
+    LOTTE_GIANTS("롯데 자이언츠"),
+    NC_DINOS("NC 다이노스"),
+    SSG_LANDERS("SSG 랜더스"),
+    SAMSUNG_LIONS("삼성 라이온즈"),
+    KT_WIZ("KT 위즈"),;
+
+    private final String name;
+
+    public TeamTag fromString(String name){
+        for (TeamTag teamTag : TeamTag.values()) {
+            if (teamTag.name.equals(name)) {
+                return teamTag;
+            }
+        }
+        throw new IllegalArgumentException("No enum constant " + name);
+    }
path: src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**`fromString` 메서드를 static으로 변경 필요**

`fromString` 메서드가 인스턴스 메서드로 정의되어 있습니다. 이는 이미 존재하는 TeamTag 인스턴스에서 호출해야 한다는 의미인데, 이 메서드의 목적(문자열을 enum으로 변환)을 고려하면 논리적으로 맞지 않습니다. 이 메서드는 static으로 정의되어야 합니다.

```diff
- public TeamTag fromString(String name){
+ public static TeamTag fromString(String name){
    for (TeamTag teamTag : TeamTag.values()) {
        if (teamTag.name.equals(name)) {
            return teamTag;
        }
    }
    throw new IllegalArgumentException("No enum constant " + name);
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    public static TeamTag fromString(String name){
        for (TeamTag teamTag : TeamTag.values()) {
            if (teamTag.name.equals(name)) {
                return teamTag;
            }
        }
        throw new IllegalArgumentException("No enum constant " + name);
    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java
around lines 20 to 27, the fromString method is currently an instance method but
should be static because it converts a string to a TeamTag enum and does not
depend on instance state. Change the method signature to static and ensure it
can be called without an instance.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit b11a991

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T02:17:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,16 @@
+package com.playus.communityservice.domain.post.dto.post_delete;
+
+import lombok.Builder;
+
+@Builder
+public record PostDeleteResponse(
+        boolean success,
+        String message
+) {
+    public static PostDeleteResponse of(boolean success, String message) {
+        return PostDeleteResponse.builder()
+                .success(true)
+                .message("게시물이 삭제되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**팩토리 메서드의 파라미터 사용 방식 개선 필요**

현재 `of` 메서드는 `success`와 `message` 파라미터를 받고 있지만 사용하지 않고 있습니다. 대신 항상 `true`와 고정된 메시지를 사용합니다. 이는 API 사용자에게 혼란을 줄 수 있습니다.


다음과 같이 수정하는 것을 권장합니다:

```diff
- public static PostDeleteResponse of(boolean success, String message) {
+ public static PostDeleteResponse of() {
    return PostDeleteResponse.builder()
            .success(true)
            .message("게시물이 삭제되었습니다.")
            .build();
}
```

또는 파라미터의 의도가 있다면 다음과 같이 수정할 수 있습니다:

```diff
public static PostDeleteResponse of(boolean success, String message) {
    return PostDeleteResponse.builder()
-            .success(true)
-            .message("게시물이 삭제되었습니다.")
+            .success(success)
+            .message(message != null ? message : "게시물이 삭제되었습니다.")
            .build();
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    public static PostDeleteResponse of(boolean success, String message) {
        return PostDeleteResponse.builder()
-            .success(true)
-            .message("게시물이 삭제되었습니다.")
+            .success(success)
+            .message(message != null ? message : "게시물이 삭제되었습니다.")
            .build();
    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java
lines 10 to 15, the static factory method 'of' takes parameters 'success' and
'message' but does not use them, always setting success to true and a fixed
message. To fix this, modify the method to use the passed parameters by setting
success to the 'success' argument and message to the 'message' argument,
ensuring the method behaves as expected and avoids confusion for API users.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,42 @@
+package com.playus.communityservice.global.config.jwt;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+@Getter
+@AllArgsConstructor
+public class JwtUser implements UserDetails {
+    private final Long userId;
+    private final String role;
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return null;
+    }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**getAuthorities() 메서드 구현 개선 필요**

현재 getAuthorities() 메서드는 null을 반환하고 있는데, 이는 Spring Security의 인가(authorization) 메커니즘에서 문제를 일으킬 수 있습니다. role 필드를 적절한 GrantedAuthority 컬렉션으로 변환하여 반환하는 것이 바람직합니다.


```diff
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
-    return null;
+    return Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role));
}
```

위의 코드를 적용하려면 필요한 import 문도 추가해야 합니다:
```java
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.Collections;
```

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java
around lines 17 to 19, the getAuthorities() method currently returns null, which
can cause issues in Spring Security's authorization process. Modify this method
to convert the existing role field into a Collection of GrantedAuthority
objects, for example by returning a singleton list containing a new
SimpleGrantedAuthority with the role. Also, add the necessary imports for
SimpleGrantedAuthority and Collections to support this change.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
+
+        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+        if (header != null && header.startsWith("Bearer ")) {
+            String token = header.substring(7);
+            try {
+                if (!jwtUtil.isExpired(token)) {
+                    Long userId = Long.parseLong(jwtUtil.getUserId(token));
+                    String role = jwtUtil.getRole(token);
+
+                    JwtUser jwtUser = new JwtUser(userId, role);
+                    Authentication auth = new UsernamePasswordAuthenticationToken(
+                            jwtUser, null, jwtUser.getAuthorities()
+                    );
+                    SecurityContextHolder.getContext().setAuthentication(auth);
+                }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**인증 처리 시 예외 처리 강화 필요**

현재 코드는 토큰이 만료되지 않은 경우에만 인증을 처리하고 있습니다. 토큰 만료 여부를 체크한 후 만료된 경우에 대한 명시적인 처리(예: 응답 헤더에 토큰 갱신 필요 표시)나 로깅이 없습니다. 이로 인해 클라이언트는 왜 인증이 실패했는지 알 수 없을 수 있습니다.


또한 jwtUser.getAuthorities()는 현재 JwtUser 구현에서 null을 반환하므로, 이 부분도 함께 수정해야 합니다.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
around lines 40 to 49, enhance exception handling by explicitly managing expired
tokens with appropriate logging and response headers to inform the client about
token renewal needs. Additionally, update the JwtUser class or its usage so that
getAuthorities() returns a valid collection of authorities instead of null,
ensuring proper authentication context setup.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
+
+        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+        if (header != null && header.startsWith("Bearer ")) {
+            String token = header.substring(7);
+            try {
+                if (!jwtUtil.isExpired(token)) {
+                    Long userId = Long.parseLong(jwtUtil.getUserId(token));
+                    String role = jwtUtil.getRole(token);
+
+                    JwtUser jwtUser = new JwtUser(userId, role);
+                    Authentication auth = new UsernamePasswordAuthenticationToken(
+                            jwtUser, null, jwtUser.getAuthorities()
+                    );
+                    SecurityContextHolder.getContext().setAuthentication(auth);
+                }
+            } catch (JwtException | IllegalArgumentException e) {
+                log.debug("JWT 인증 실패: {}", e.getMessage());
+            }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**예외 처리 개선 및 보안 로깅**

현재 JWT 인증 실패 시 debug 레벨로만 로깅하고 예외를 무시하고 있습니다. 보안 관련 이슈는 적절한 레벨(예: warn)으로 로깅하고, 필요에 따라 특정 예외 유형(만료된 토큰, 잘못된 서명 등)에 따른 차별화된 처리를 고려해 보세요. 또한, 예외 메시지에 민감한 정보가 포함되지 않도록 주의해야 합니다.


```diff
- } catch (JwtException | IllegalArgumentException e) {
-     log.debug("JWT 인증 실패: {}", e.getMessage());
+ } catch (JwtException | IllegalArgumentException e) {
+     log.warn("JWT 인증 실패: {}", e.getClass().getSimpleName());
+     // 추가 예외 처리 로직
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
            } catch (JwtException | IllegalArgumentException e) {
                log.warn("JWT 인증 실패: {}", e.getClass().getSimpleName());
                // 추가 예외 처리 로직
            }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
around lines 50 to 52, improve exception handling by changing the log level from
debug to warn for JWT authentication failures to highlight security issues.
Additionally, differentiate handling based on specific JWT exceptions like
expired token or invalid signature to provide more precise responses. Ensure
that logged messages do not expose sensitive information by sanitizing or
generalizing exception details.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,58 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import com.playus.communityservice.global.exception.EntityNotFoundException;
+import com.playus.communityservice.global.exception.UnauthorizedAccessException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+
+    @Transactional
+    public PostCreateResponse createPost(PostCreateRequest request, JwtUser user, TeamTag tag) {
+        Post post = Post.create(user.getId(), request.title(), request.content(), tag, request.jwpDate());
+        postRepository.save(post);
+
+        return PostCreateResponse.of(post.getId(), "게시물 생성이 완료되었습니다.");
+    }
+
+    @Transactional
+    public PostUpdateResponse updatePost(PostUpdateRequest request, JwtUser user, TeamTag tag) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new EntityNotFoundException("게시글"));
+
+        if (!post.getWriterId().equals(user.getId())) {
+            throw new UnauthorizedAccessException("게시글");
+        }
+
+        post.updateAll(request.title(), request.content(), TeamTag.DOOSAN_BEARS, false, request.jwpDate());
+        return PostUpdateResponse.fo(true, "게시물이 수정되었습니다.");
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**updatePost 메서드에서 발견된 문제점.**

1. `TeamTag tag` 매개변수를 받고 있으나 사용하지 않고 `TeamTag.DOOSAN_BEARS`가 하드코딩되어 있습니다.
2. `isSecret` 값이 항상 false로 하드코딩되어 있어 유연성이 떨어집니다.
3. 응답 객체 생성 메서드에 오타가 있습니다: `PostUpdateResponse.fo()` -> `PostUpdateResponse.of()`


다음과 같이 수정하세요:

```diff
-        post.updateAll(request.title(), request.content(), TeamTag.DOOSAN_BEARS, false, request.jwpDate());
-        return PostUpdateResponse.fo(true, "게시물이 수정되었습니다.");
+        post.updateAll(request.title(), request.content(), tag, post.isSecret(), request.jwpDate());
+        return PostUpdateResponse.of(true, "게시물이 수정되었습니다.");
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    @Transactional
    public PostUpdateResponse updatePost(PostUpdateRequest request, JwtUser user, TeamTag tag) {
        Post post = postRepository.findById(request.postId())
                .orElseThrow(() -> new EntityNotFoundException("게시글"));

        if (!post.getWriterId().equals(user.getId())) {
            throw new UnauthorizedAccessException("게시글");
        }

        post.updateAll(request.title(), request.content(), tag, post.isSecret(), request.jwpDate());
        return PostUpdateResponse.of(true, "게시물이 수정되었습니다.");
    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/service/PostService.java
around lines 33 to 44, the updatePost method has three issues: the TeamTag
parameter 'tag' is unused and instead TeamTag.DOOSAN_BEARS is hardcoded, the
isSecret parameter is always set to false reducing flexibility, and the response
creation method is incorrectly called as PostUpdateResponse.fo() instead of
PostUpdateResponse.of(). Fix these by replacing the hardcoded
TeamTag.DOOSAN_BEARS with the passed 'tag' parameter, use a proper isSecret
value from the request or method parameters instead of false, and correct the
method call to PostUpdateResponse.of() when returning the response.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit c113a37

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,50 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<PostCreateResponse> create(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostCreateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostCreateResponse response = postService.createPost(request, user, tag);
+        URI location = URI.create("/post/" + response.postId());
+        return ResponseEntity.created(location).body(response);
+    }
+
+    @PatchMapping
+    public ResponseEntity<PostUpdateResponse> update(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostUpdateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostUpdateResponse response = postService.updatePost(request, user, tag);
+        return ResponseEntity.ok(response);
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**@PatchMapping 경로 템플릿이 누락되었습니다.**

현재 메서드 시그니처에는 `@PathVariable TeamTag tag`가 포함되어 있지만, 이에 대응하는 경로 변수를 @PatchMapping 어노테이션에서 지정하지 않았습니다. 이로 인해 런타임 시 오류가 발생할 것입니다.

다음과 같이 수정해주세요:

```diff
-@PatchMapping
+@PatchMapping("/{tag}")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    @PatchMapping("/{tag}")
    public ResponseEntity<PostUpdateResponse> update(@PathVariable TeamTag tag,
                                                     @Valid @RequestBody PostUpdateRequest request,
                                                     @AuthenticationPrincipal JwtUser user) {
        PostUpdateResponse response = postService.updatePost(request, user, tag);
        return ResponseEntity.ok(response);
    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
around lines 36 to 42, the @PatchMapping annotation is missing the path template
that includes the path variable 'tag'. To fix this, add the appropriate path
template with the variable placeholder (e.g., "/{tag}") to the @PatchMapping
annotation so that the @PathVariable TeamTag tag can be correctly bound at
runtime.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit c113a37

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,50 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<PostCreateResponse> create(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostCreateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostCreateResponse response = postService.createPost(request, user, tag);
+        URI location = URI.create("/post/" + response.postId());
+        return ResponseEntity.created(location).body(response);
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**@PostMapping 경로 템플릿이 누락되었습니다.**

현재 메서드 시그니처에는 `@PathVariable TeamTag tag`가 포함되어 있지만, 이에 대응하는 경로 변수를 @PostMapping 어노테이션에서 지정하지 않았습니다. 이로 인해 런타임 시 오류가 발생할 것입니다.

다음과 같이 수정해주세요:

```diff
-@PostMapping
+@PostMapping("/{tag}")
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    @PostMapping("/{tag}")
    public ResponseEntity<PostCreateResponse> create(@PathVariable TeamTag tag,
                                                     @Valid @RequestBody PostCreateRequest request,
                                                     @AuthenticationPrincipal JwtUser user) {
        PostCreateResponse response = postService.createPost(request, user, tag);
        URI location = URI.create("/post/" + response.postId());
        return ResponseEntity.created(location).body(response);
    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
around lines 27 to 34, the @PostMapping annotation is missing the path template
that includes the path variable 'tag' required by the method parameter
@PathVariable TeamTag tag. To fix this, add the appropriate path template with
the variable placeholder (e.g., "/{tag}") to the @PostMapping annotation so it
matches the method signature and prevents runtime errors.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit c113a37

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,64 @@
+package com.playus.communityservice.global.exception;
+
+import com.playus.communityservice.domain.post.controller.PostController;
+import com.playus.communityservice.global.response.ErrorResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.server.ResponseStatusException;
+
+
+@Slf4j
+@RestControllerAdvice(assignableTypes = {
+        PostController.class
+})
+public class ExceptionAdvice {
+
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<String> bindExceptionHandler(BindException e) {
+        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
+        log.warn("Validation Error: {}", errorMessage);
+        return ResponseEntity.badRequest().body(errorMessage);
+    }
path: src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**오류 응답 형식의 일관성 문제**

다른 예외 핸들러는 `ErrorResponse` 객체를 반환하지만, 이 메서드는 `String`을 직접 반환합니다. API 응답 형식의 일관성을 유지하는 것이 중요합니다.

다음과 같이 수정해주세요:

```diff
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(BindException.class)
-public ResponseEntity<String> bindExceptionHandler(BindException e) {
+public ErrorResponse bindExceptionHandler(BindException e) {
    String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
    log.warn("Validation Error: {}", errorMessage);
-    return ResponseEntity.badRequest().body(errorMessage);
+    return ErrorResponse.badRequestError(errorMessage);
}
```

이를 위해 ErrorResponse 클래스에 badRequestError 메서드를 추가해야 할 수도 있습니다.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public ErrorResponse bindExceptionHandler(BindException e) {
        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
        log.warn("Validation Error: {}", errorMessage);
        return ErrorResponse.badRequestError(errorMessage);
    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
around lines 21 to 27, the bindExceptionHandler method returns a String directly
instead of an ErrorResponse object like other exception handlers, causing
inconsistency in API error response formats. Modify this method to return a
ResponseEntity containing an ErrorResponse object with the error message. If
necessary, add a static badRequestError method to the ErrorResponse class to
create this standardized error response.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit c113a37

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,64 @@
+package com.playus.communityservice.global.exception;
+
+import com.playus.communityservice.domain.post.controller.PostController;
+import com.playus.communityservice.global.response.ErrorResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.server.ResponseStatusException;
+
+
+@Slf4j
+@RestControllerAdvice(assignableTypes = {
+        PostController.class
+})
+public class ExceptionAdvice {
+
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<String> bindExceptionHandler(BindException e) {
+        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
+        log.warn("Validation Error: {}", errorMessage);
+        return ResponseEntity.badRequest().body(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.UNAUTHORIZED)
+    @ExceptionHandler(ResponseStatusException.class)
+    public ErrorResponse responseStatusExHandler(ResponseStatusException e) {
+        String errorMessage = e.getMessage();
+        log.warn("INVALID_TOKEN Error: {}", errorMessage);
+        return ErrorResponse.unauthorizedError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.NOT_FOUND)
+    @ExceptionHandler({
+            EntityNotFoundException.class
+    })
+    public ErrorResponse handleEntityNotFoundException(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Entity Not Found Error: {}", errorMessage);
+        return ErrorResponse.notFoundError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.FORBIDDEN)
+    @ExceptionHandler({
+            UnauthorizedAccessException.class
+    })
+    public ErrorResponse handleUnauthorizedAccessException(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Unauthorized Access Error: {}", errorMessage);
+        return ErrorResponse.forbiddenError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    @ExceptionHandler(Exception.class)
+    public ResponseEntity<String> otherExceptionHandler(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Unexpected Error: {}", errorMessage);
+        return ResponseEntity.internalServerError().body("서버 에러가 발생했습니다! 관리자에게 문의해 주세요!");
+    }
path: src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**오류 응답 형식의 일관성 문제**

다른 예외 핸들러는 `ErrorResponse` 객체를 반환하지만, 이 메서드는 `String`을 직접 반환합니다. API 응답 형식의 일관성을 유지하는 것이 중요합니다.

다음과 같이 수정해주세요:

```diff
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ExceptionHandler(Exception.class)
-public ResponseEntity<String> otherExceptionHandler(Exception e) {
+public ErrorResponse otherExceptionHandler(Exception e) {
    String errorMessage = e.getMessage();
    log.error("Unexpected Error: {}", errorMessage);
-    return ResponseEntity.internalServerError().body("서버 에러가 발생했습니다! 관리자에게 문의해 주세요!");
+    return ErrorResponse.serverError("서버 에러가 발생했습니다! 관리자에게 문의해 주세요!");
}
```

이를 위해 ErrorResponse 클래스에 serverError 메서드를 추가해야 할 수도 있습니다.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public ErrorResponse otherExceptionHandler(Exception e) {
        String errorMessage = e.getMessage();
        log.error("Unexpected Error: {}", errorMessage);
        return ErrorResponse.serverError("서버 에러가 발생했습니다! 관리자에게 문의해 주세요!");
    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
around lines 57 to 63, the otherExceptionHandler method returns a plain String
instead of an ErrorResponse object, causing inconsistency in API error response
formats. Modify this method to return an ErrorResponse instance similar to other
handlers, and if necessary, add a static serverError method to the ErrorResponse
class to create a standardized server error response. Update the return type to
ResponseEntity<ErrorResponse> and ensure the response body uses this
ErrorResponse object for consistency.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit c113a37

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**응답 상태 코드 불일치**

API 명세에서는 게시글 생성 응답 코드를 `200 OK`로 지정했지만, 실제 컨트롤러 구현에서는 `201 Created`를 반환합니다. 이 불일치를 해결해야 합니다.

다음과 같이 수정해주세요:

```diff
    @ApiResponses(value = {
            @ApiResponse(
-                    responseCode = "200", description = "생성 성공",
+                    responseCode = "201", description = "생성 성공",
                    content = @Content(
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    @ApiResponses(value = {
            @ApiResponse(
-                   responseCode = "200", description = "생성 성공",
+                   responseCode = "201", description = "생성 성공",
                    content = @Content(
                            mediaType = APPLICATION_JSON_VALUE,
                            examples = @ExampleObject(
                                    name = "게시글 생성 응답 예시",
                                    value = """
                                    {
                                      "postId" : 1,
                                      "message" : "게시물 생성이 완료되었습니다."
                                    }
                                    """
                            )
                    )
            )
    })
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
between lines 46 and 62, the API response code for post creation is documented
as 200 OK, but the controller actually returns 201 Created. Update the
@ApiResponse annotation to use responseCode = "201" to match the controller's
behavior and ensure consistency between the specification and implementation.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1
+                                      "jwpDate" : "2025-05-01"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**JSON 예시에 쉼표 누락**

게시글 수정 요청 예시의 JSON에 쉼표가 누락되어 있습니다. 이는 실제로 사용할 때 클라이언트 쪽에서 오류를 발생시킬 수 있습니다.

다음과 같이 수정해주세요:

```diff
                                    {
                                      "title": "오늘 경기 재밌었어요!",
                                      "image": "2",
-                                      "content": "긴장하면서 시청했네요."
-                                      "postId": 1
+                                      "content": "긴장하면서 시청했네요.",
+                                      "postId": 1,
                                      "jwpDate" : "2025-05-01"
                                    }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
                                    {
                                      "title": "오늘 경기 재밌었어요!",
                                      "image": "2",
                                      "content": "긴장하면서 시청했네요.",
                                      "postId": 1,
                                      "jwpDate" : "2025-05-01"
                                    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
around lines 118 to 120, the JSON example for the post update request is missing
a comma between the "postId" and "jwpDate" fields. Add a comma after the
"postId": 1 line to ensure the JSON is valid and prevent client-side errors.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**메서드 시그니처와 구현 불일치**

인터페이스의 `createPost` 메서드 시그니처에는 `TeamTag` 매개변수가 포함되어 있지 않지만, 컨트롤러 구현에서는 이를 요구합니다. 이러한 불일치는 Swagger 문서와 실제 구현 간의 혼란을 초래할 수 있습니다.

다음과 같이 수정해주세요:

```diff
-    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
+    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request);
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request);
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
at line 63, the createPost method signature lacks the TeamTag parameter required
by the controller implementation. To fix this, update the createPost method
signature to include the TeamTag parameter so it matches the controller's
implementation and Swagger documentation, ensuring consistency across interface
and implementation.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**JSON 예시에 쉼표 누락**

게시글 생성 요청 예시의 JSON에 쉼표가 누락되어 있습니다. 이는 실제로 사용할 때 클라이언트 쪽에서 오류를 발생시킬 수 있습니다.

다음과 같이 수정해주세요:

```diff
                                    {
                                      "title": "오늘 경기 재밌었어요!",
                                      "image": "1",
-                                      "content": "LG가 이길 줄 알았죠!"
+                                      "content": "LG가 이길 줄 알았죠!",
                                      "jwpDate" : "2025-05-05"
                                    }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
                                    {
                                      "title": "오늘 경기 재밌었어요!",
                                      "image": "1",
-                                      "content": "LG가 이길 줄 알았죠!"
+                                      "content": "LG가 이길 줄 알았죠!",
                                      "jwpDate" : "2025-05-05"
                                    }
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
at lines 39 to 40, the JSON example for the post creation request is missing a
comma, which will cause client-side errors. Add the missing comma after the
preceding JSON field to ensure the JSON syntax is correct and valid.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1
+                                      "jwpDate" : "2025-05-01"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "수정 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "수정 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 수정되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostUpdateResponse> updatePost(PostUpdateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**메서드 시그니처와 구현 불일치**

인터페이스의 `updatePost` 메서드 시그니처에는 `TeamTag` 매개변수가 포함되어 있지 않지만, 컨트롤러 구현에서는 이를 요구합니다. 이러한 불일치는 Swagger 문서와 실제 구현 간의 혼란을 초래할 수 있습니다.

다음과 같이 수정해주세요:

```diff
-    ResponseEntity<PostUpdateResponse> updatePost(PostUpdateRequest request);
+    ResponseEntity<PostUpdateResponse> updatePost(TeamTag tag, PostUpdateRequest request);
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
    ResponseEntity<PostUpdateResponse> updatePost(TeamTag tag, PostUpdateRequest request);
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
at line 143, the updatePost method signature lacks the TeamTag parameter that
the controller implementation requires. To fix this, add the TeamTag parameter
to the updatePost method signature in the interface so it matches the controller
implementation and Swagger documentation, ensuring consistency across the
codebase.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:17:51Z
author_association: NONE
diff_hunk: @@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import lombok.Builder;
+
+@Builder
+public record PostCreateResponse(
+        Long postId,
+        String massage
+) {
+
+    public static PostCreateResponse of(Long postId, String massage) {
+        return PostCreateResponse.builder()
+                .postId(postId)
+                .massage("게시물 생성이 완료되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 좋은 결정입니다! 오타를 수정하고 사용하지 않는 파라미터를 제거하면 코드의 명확성과 유지보수성이 향상될 것입니다. 변경 진행 감사합니다. 



ʕ•ᴥ•ʔﾉ♡

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20%F0%9F%9B%A0%EF%B8%8F%ED%8C%A9%ED%86%A0%EB%A6%AC%20%EB%A9%94%EC%84%9C%EB%93%9C%20%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%20%EB%AF%B8%EC%82%AC%EC%9A%A9%20%EB%AC%B8%EC%A0%9C%20%ED%95%B4%EA%B2%B0!%20%EB%B6%88%ED%95%84%EC%9A%94%ED%95%9C%20%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%20%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B1%B0%EB%82%98%20%EC%A0%9C%EB%8C%80%EB%A1%9C%20%ED%99%9C%EC%9A%A9%ED%95%B4%20API%20%ED%98%BC%EB%9E%80%20%EC%A4%84%EC%9D%B4%EA%B8%B0.%20%EA%B9%94%EB%81%94%ED%95%9C%20%EC%BD%94%EB%93%9C%2C%20%EA%BC%AD%20%EA%B2%BD%ED%97%98%ED%95%B4%EB%B3%B4%EC%84%B8%EC%9A%94!&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075964)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:28:28Z
author_association: NONE
diff_hunk: @@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import lombok.Builder;
+
+@Builder
+public record PostCreateResponse(
+        Long postId,
+        String massage
+) {
+
+    public static PostCreateResponse of(Long postId, String massage) {
+        return PostCreateResponse.builder()
+                .postId(postId)
+                .massage("게시물 생성이 완료되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
user: login: gachaemin
body: @coderabbitai
오타 수정 후 파라미터 제거하도록 하겠습니다.
created_at: 2025-05-15T02:28:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import lombok.Builder;
+
+@Builder
+public record PostCreateResponse(
+        Long postId,
+        String massage
+) {
+
+    public static PostCreateResponse of(Long postId, String massage) {
+        return PostCreateResponse.builder()
+                .postId(postId)
+                .massage("게시물 생성이 완료되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 좋은 결정입니다! 오타 수정과 함께 불필요한 파라미터를 제거하면 코드가 더 명확해질 것입니다. 변경 후 코드가 더 직관적이고 유지보수하기 쉬워질 겁니다. 👍

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:28:54Z
author_association: NONE
diff_hunk: @@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import lombok.Builder;
+
+@Builder
+public record PostCreateResponse(
+        Long postId,
+        String massage
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
user: login: gachaemin
body: @coderabbitai
오타 수정하도록 하겠습니다.
created_at: 2025-05-15T02:28:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,17 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import lombok.Builder;
+
+@Builder
+public record PostCreateResponse(
+        Long postId,
+        String massage
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateResponse.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 알겠습니다. 오타를 수정해 주셔서 감사합니다! 👍

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20%EB%8D%95%EB%B6%84%EC%97%90%20API%20%EC%9D%91%EB%8B%B5%20%ED%95%84%EB%93%9C%EB%AA%85%20%EC%98%A4%ED%83%80%EB%A5%BC%20%EB%B0%94%EB%A1%9C%EC%9E%A1%EC%95%84%20%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%20%ED%98%BC%EB%9E%80%20%EB%B0%A9%EC%A7%80!%20%EC%9E%91%EC%9D%80%20%EC%8B%A4%EC%88%98%EB%8F%84%20%ED%81%B0%20%EB%AC%B8%EC%A0%9C%EB%A1%9C%20%EB%B2%88%EC%A7%80%EA%B8%B0%20%EC%A0%84%EC%97%90%20%EA%BC%AD%20%EC%A0%90%EA%B2%80%ED%95%98%EC%84%B8%EC%9A%94.%20%F0%9F%90%B0%E2%9C%A8%20%23%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075963)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:29:14Z
author_association: NONE
diff_hunk: @@ -0,0 +1,16 @@
+package com.playus.communityservice.domain.post.dto.post_update;
+
+import lombok.Builder;
+
+@Builder
+public record PostUpdateResponse(
+        boolean success,
+        String message
+) {
+    public static PostUpdateResponse fo(boolean success, String message) {
+        return PostUpdateResponse.builder()
+                .success(true)
+                .message("게시물이 수정되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java
user: login: gachaemin
body: @coderabbitai
코드 수정 후 매개 변수 수정하도록 하겠습니다.
created_at: 2025-05-15T02:29:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,16 @@
+package com.playus.communityservice.domain.post.dto.post_update;
+
+import lombok.Builder;
+
+@Builder
+public record PostUpdateResponse(
+        boolean success,
+        String message
+) {
+    public static PostUpdateResponse fo(boolean success, String message) {
+        return PostUpdateResponse.builder()
+                .success(true)
+                .message("게시물이 수정되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_update/PostUpdateResponse.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 코드 수정 계획 감사합니다. 메서드 이름과 매개변수 처리를 수정하시면 코드의 명확성과 기능이 개선될 것입니다. 수정 후 더 나은 코드가 될 것으로 기대합니다!

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:29:39Z
author_association: NONE
diff_hunk: @@ -0,0 +1,16 @@
+package com.playus.communityservice.domain.post.dto.post_delete;
+
+import lombok.Builder;
+
+@Builder
+public record PostDeleteResponse(
+        boolean success,
+        String message
+) {
+    public static PostDeleteResponse of(boolean success, String message) {
+        return PostDeleteResponse.builder()
+                .success(true)
+                .message("게시물이 삭제되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java
user: login: gachaemin
body: @coderabbitai
수정하도록 하겠습니다.
created_at: 2025-05-15T02:30:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,16 @@
+package com.playus.communityservice.domain.post.dto.post_delete;
+
+import lombok.Builder;
+
+@Builder
+public record PostDeleteResponse(
+        boolean success,
+        String message
+) {
+    public static PostDeleteResponse of(boolean success, String message) {
+        return PostDeleteResponse.builder()
+                .success(true)
+                .message("게시물이 삭제되었습니다.")
+                .build();
+    }
path: src/main/java/com/playus/communityservice/domain/post/dto/post_delete/PostDeleteResponse.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 수정하시겠다는 의사에 감사드립니다. 해당 변경으로 코드의 명확성이 향상될 것입니다. 👍

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20%ED%8C%A9%ED%86%A0%EB%A6%AC%20%EB%A9%94%EC%84%9C%EB%93%9C%20%ED%8C%8C%EB%9D%BC%EB%AF%B8%ED%84%B0%EB%A5%BC%20%EC%A0%9C%EB%8C%80%EB%A1%9C%20%ED%99%9C%EC%9A%A9%ED%95%B4%20API%20%ED%98%BC%EB%9E%80%20%EB%B0%A9%EC%A7%80!%20success%EC%99%80%20message%EB%A5%BC%20%EC%9D%B8%EC%9E%90%EB%A1%9C%20%EB%B0%9B%EC%95%84%20%EC%9C%A0%EC%97%B0%ED%95%9C%20%EC%9D%91%EB%8B%B5%20%EC%83%9D%EC%84%B1%20%EA%B0%80%EB%8A%A5%ED%95%98%EA%B2%8C%20%EA%B0%9C%EC%84%A0%ED%95%98%EC%84%B8%EC%9A%94%20%F0%9F%9B%A0%EF%B8%8F%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94!&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075968)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:31:00Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
controller 수정 후 specification을 까먹었습니다. 바로 수정하겠습니다.
created_at: 2025-05-15T02:31:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 이해했습니다! 컨트롤러를 수정한 후 명세(specification)도 함께 업데이트하는 것은 놓치기 쉬운 부분입니다. 빠르게 인지하고 수정하겠다는 의지 감사합니다. 👍

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=API%20%EB%AA%85%EC%84%B8%EC%99%80%20%EC%BB%A8%ED%8A%B8%EB%A1%A4%EB%9F%AC%20%EC%9D%91%EB%8B%B5%20%EC%BD%94%EB%93%9C%20%EB%B6%88%EC%9D%BC%EC%B9%98%20%EB%AC%B8%EC%A0%9C%20%ED%95%B4%EA%B2%B0!%20201%20Created%EB%A1%9C%20%EB%A7%9E%EC%B6%B0%20%EC%8B%A0%EB%A2%B0%EB%8F%84%20UP%20%F0%9F%9A%80%20%EC%BD%94%EB%93%9C%20%EC%9D%BC%EA%B4%80%EC%84%B1%EC%9D%80%20%ED%95%84%EC%88%98%EC%9E%85%EB%8B%88%EB%8B%A4.%20%40coderabbitai%EC%99%80%20%ED%95%A8%EA%BB%98%20%EC%99%84%EB%B2%BD%ED%95%9C%20%EC%BD%94%EB%93%9C%20%EA%B4%80%EB%A6%AC%ED%95%98%EC%84%B8%EC%9A%94!%20%F0%9F%9B%A0%EF%B8%8F&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075986)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:32:07Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1
+                                      "jwpDate" : "2025-05-01"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
바로 반영하겠습니다.
created_at: 2025-05-15T02:32:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1
+                                      "jwpDate" : "2025-05-01"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 빠른 확인과 조치에 감사합니다! 코드 품질 향상에 기여해 주셔서 감사합니다. 🙌

<!--  -->

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%EA%B0%80%20JSON%20%EC%98%88%EC%8B%9C%20%EC%89%BC%ED%91%9C%20%EB%88%84%EB%9D%BD%20%EB%AC%B8%EC%A0%9C%EB%A5%BC%20%EC%A0%95%ED%99%95%ED%9E%88%20%EC%A7%9A%EC%96%B4%EC%A4%AC%EC%96%B4%EC%9A%94!%20%EC%9E%91%EC%9D%80%20%EC%8B%A4%EC%88%98%EB%8F%84%20%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%20%EC%98%A4%EB%A5%98%EB%A1%9C%20%EC%9D%B4%EC%96%B4%EC%A7%88%20%EC%88%98%20%EC%9E%88%EC%9C%BC%EB%8B%88%20%EA%BC%BC%EA%BC%BC%ED%95%9C%20%EB%A6%AC%EB%B7%B0%EA%B0%80%20%ED%95%84%EC%88%98%EC%9E%85%EB%8B%88%EB%8B%A4.%F0%9F%9B%A0%EF%B8%8F%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94!&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075988)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T02:32:42Z
author_association: NONE
diff_hunk: @@ -0,0 +1,28 @@
+package com.playus.communityservice.domain.post.enums;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public enum TeamTag {
+    DOOSAN_BEARS("두산 베어스"),
+    HANWHA_EAGLES("한화 이글스"),
+    KIA_TIGERS("KIA 타이거즈"),
+    KIWOOM_HEROES("키움 히어로즈"),
+    LG_TWINS("LG 트윈스"),
+    LOTTE_GIANTS("롯데 자이언츠"),
+    NC_DINOS("NC 다이노스"),
+    SSG_LANDERS("SSG 랜더스"),
+    SAMSUNG_LIONS("삼성 라이온즈"),
+    KT_WIZ("KT 위즈"),;
+
+    private final String name;
+
+    public TeamTag fromString(String name){
+        for (TeamTag teamTag : TeamTag.values()) {
+            if (teamTag.name.equals(name)) {
+                return teamTag;
+            }
+        }
+        throw new IllegalArgumentException("No enum constant " + name);
+    }
path: src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java
user: login: gachaemin
body: @coderabbitai
바로 수정하겠습니다.
created_at: 2025-05-15T03:01:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,28 @@
+package com.playus.communityservice.domain.post.enums;
+
+import lombok.RequiredArgsConstructor;
+
+@RequiredArgsConstructor
+public enum TeamTag {
+    DOOSAN_BEARS("두산 베어스"),
+    HANWHA_EAGLES("한화 이글스"),
+    KIA_TIGERS("KIA 타이거즈"),
+    KIWOOM_HEROES("키움 히어로즈"),
+    LG_TWINS("LG 트윈스"),
+    LOTTE_GIANTS("롯데 자이언츠"),
+    NC_DINOS("NC 다이노스"),
+    SSG_LANDERS("SSG 랜더스"),
+    SAMSUNG_LIONS("삼성 라이온즈"),
+    KT_WIZ("KT 위즈"),;
+
+    private final String name;
+
+    public TeamTag fromString(String name){
+        for (TeamTag teamTag : TeamTag.values()) {
+            if (teamTag.name.equals(name)) {
+                return teamTag;
+            }
+        }
+        throw new IllegalArgumentException("No enum constant " + name);
+    }
path: src/main/java/com/playus/communityservice/domain/post/enums/TeamTag.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 감사합니다! 변경 사항 적용해 주시면 됩니다. 👍

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T03:01:53Z
author_association: NONE
diff_hunk: @@ -0,0 +1,147 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!",
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "201", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1,
+                                      "jwpDate" : "2025-05-01"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "수정 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "수정 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 수정되었습니다."
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**boolean 타입 필드가 문자열로 표기되어 있습니다.**

`success` 필드는 `PostUpdateResponse` 클래스에서 boolean 타입으로 정의되어 있을 것으로 예상되지만, 응답 예시에서는 문자열 `"true"`로 표시되어 있습니다. JSON에서 boolean 값은 따옴표 없이 표기해야 합니다.

```diff
{
-    "success" : "true",
+    "success" : true,
    "message" : "게시물이 수정되었습니다."
}
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
                                        "success" : true,
                                        "message" : "게시물이 수정되었습니다."
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
at lines 137 to 138, the JSON response example incorrectly represents the
boolean field "success" as a string "true". Update the response example to use a
boolean value true without quotes to correctly reflect the boolean type defined
in PostUpdateResponse.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 394fc5f

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T07:15:38Z
author_association: NONE
diff_hunk: @@ -0,0 +1,147 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!",
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "201", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**boolean 타입 필드가 문자열로 표기되어 있습니다.**

`success` 필드는 `PostDeleteResponse` 클래스에서 boolean 타입으로 정의되어 있지만, 응답 예시에서는 문자열 `"true"`로 표시되어 있습니다. JSON에서 boolean 값은 따옴표 없이 표기해야 합니다.

```diff
{
-    "success" : "true",
+    "success" : true,
    "message" : "게시물이 삭제되었습니다."
}
```



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion
                                        "success" : true,
                                        "message" : "게시물이 삭제되었습니다."
```

</details>

<!-- suggestion_end -->

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
In
src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
at lines 95 to 96, the JSON response example incorrectly represents the boolean
field "success" as a string "true". Update the response example to use the
boolean value true without quotes to correctly reflect the boolean type defined
in the PostDeleteResponse class.
```

</details>

<!-- This is an auto-generated reply by CodeRabbit -->

✅ Addressed in commit 394fc5f

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-15T07:15:39Z
author_association: NONE
diff_hunk: @@ -0,0 +1,147 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!",
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "201", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1,
+                                      "jwpDate" : "2025-05-01"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "수정 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "수정 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 수정되었습니다."
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
수정하겠습니다.
created_at: 2025-05-15T07:17:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!",
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "201", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
수정하겠습니다.
created_at: 2025-05-15T07:17:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!",
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "201", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1,
+                                      "jwpDate" : "2025-05-01"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "수정 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "수정 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 수정되었습니다."
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 감사합니다! 좋은 JSON 포맷으로 수정해 주셔서 감사합니다. 👍

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20JSON%20%EC%9D%91%EB%8B%B5%20%EC%98%88%EC%8B%9C%EC%97%90%EC%84%9C%20boolean%20%ED%95%84%EB%93%9C%EB%A5%BC%20%EB%AC%B8%EC%9E%90%EC%97%B4%EB%A1%9C%20%ED%91%9C%EA%B8%B0%ED%95%98%EB%8A%94%20%EC%8B%A4%EC%88%98%EB%A5%BC%20%EC%9E%A1%EC%95%84%EC%A4%AC%EC%96%B4%EC%9A%94!%20%ED%83%80%EC%9E%85%20%EC%9D%BC%EA%B4%80%EC%84%B1%20%EC%9C%A0%EC%A7%80%EB%A1%9C%20%EB%B2%84%EA%B7%B8%20%EC%98%88%EB%B0%A9%EC%97%90%20%ED%81%B0%20%EB%8F%84%EC%9B%80%F0%9F%91%8D%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94!%20%23%EC%BD%94%EB%93%9C%EB%A6%AC%EB%B7%B0%20%23%EA%B0%9C%EB%B0%9C%ED%8C%81&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090456464)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T07:18:09Z
author_association: NONE
diff_hunk: @@ -0,0 +1,147 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!",
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "201", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(TeamTag tag, PostCreateRequest request, JwtUser user);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 감사합니다! 수정 계획에 감사드립니다. 문제를 해결해 주셔서 감사합니다.

(｀･ω･´)ゞ

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-15T07:18:12Z
author_association: NONE
diff_hunk: @@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
user: login: Minminminwoo
body: 프론트와 확인하다보니 엑세스 토큰을 AUTHORIZATION HttpHeader 가 아닌 쿠키로 전달하기로 방식이 바뀌었습니다. user 레포지토리에서 닉네임 중복 방지/프로필 수정하는 api 작성 후 pr 되면 그때 적용하시면 좋을것 같습니다.
created_at: 2025-05-15T09:20:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: Minminminwoo
body: 인증된 유저인지 판별을 위해 요청 보낼때 헤더에 엑세스 토큰을 담아보내줘야 해서, swagger 코드 description = "게시글을 작성합니다.", 밑에 security    = @SecurityRequirement(name = "AccessCookie"),
            parameters  = @Parameter(
                    name        = "Access",
                    description = "JWT access token (쿠키)",
                    in          = ParameterIn.COOKIE,
                    required    = true,
                    example     = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
            ), 이 security와 parameters 설정도 넣어주시면 감사하겠습니다!
created_at: 2025-05-15T09:26:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
user: login: gachaemin
body: 그럼 이 부분은 일단 놔둔 상태로 merge하고 나중에 변경하도록 하겠습니다.
created_at: 2025-05-15T10:00:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: 바로 수정하도록 하겠습니다!
created_at: 2025-05-15T10:03:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
위와 같이 수정하겠습니다.
created_at: 2025-05-16T00:09:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
위와 같이 수정하겠습니다.
created_at: 2025-05-16T00:09:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1
+                                      "jwpDate" : "2025-05-01"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "수정 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "수정 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 수정되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostUpdateResponse> updatePost(PostUpdateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
위와 같이 수정하겠습니다.
created_at: 2025-05-16T00:10:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 확인했습니다. 수정해주셔서 감사합니다! 다른 도움이 필요하시면 언제든지 말씀해주세요.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:10:11Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 감사합니다! 수정해 주셔서 좋은 JSON 형식이 될 것입니다. 👍

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20JSON%20%EC%98%88%EC%8B%9C%EC%97%90%EC%84%9C%20%EC%89%BC%ED%91%9C%20%ED%95%98%EB%82%98%20%EB%B9%A0%EC%A0%B8%EB%8F%84%20%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8%20%EC%98%A4%EB%A5%98%20%EB%B0%9C%EC%83%9D!%20%EC%9E%91%EC%9D%80%20%EC%8B%A4%EC%88%98%EB%8F%84%20%ED%81%B0%20%EB%AC%B8%EC%A0%9C%EB%A1%9C%2C%20%EA%BC%BC%EA%BC%BC%ED%95%9C%20%EC%BD%94%EB%93%9C%20%EB%A6%AC%EB%B7%B0%EA%B0%80%20%ED%95%84%EC%88%98%EC%9E%85%EB%8B%88%EB%8B%A4%20%F0%9F%9B%A0%EF%B8%8F%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94!%20%23%EC%BD%94%EB%93%9C%ED%92%88%EC%A7%88%ED%96%A5%EC%83%81&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075992)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:10:19Z
author_association: NONE
diff_hunk: @@ -0,0 +1,145 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Map;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                      "jwpDate" : "2025-05-05"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "postId" : 1,
+                                      "message" : "게시물 생성이 완료되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostCreateResponse> createPost(PostCreateRequest request);
+
+    @Tag(name = "Post", description = "게시글 삭제 API")
+    @Operation(
+            summary = "게시글 삭제",
+            description = "작성자가 게시글을 삭제합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 삭제 요청 예시",
+                                    value = """
+                                    {
+                                      "postId": 1
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "삭제 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "삭제 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 삭제되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostDeleteResponse> deletePost(PostDeleteRequest request);
+
+    @Tag(name = "Post", description = "게시글 수정 API")
+    @Operation(
+            summary = "게시글 수정",
+            description = "작성자가 게시글을 수정합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 수정 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "2",
+                                      "content": "긴장하면서 시청했네요."
+                                      "postId": 1
+                                      "jwpDate" : "2025-05-01"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "수정 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "수정 응답 예시",
+                                    value = """
+                                    {
+                                        "success" : "true",
+                                        "message" : "게시물이 수정되었습니다."
+                                    }
+                                    """
+                            )
+                    )
+            )
+    })
+    ResponseEntity<PostUpdateResponse> updatePost(PostUpdateRequest request);
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 알겠습니다. 수정 제안을 받아들여 주셔서 감사합니다. 이렇게 하면 인터페이스와 구현체 간의 일관성이 유지될 것입니다.

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20%EB%8D%95%EB%B6%84%EC%97%90%20%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80%20%EA%B5%AC%ED%98%84%20%EA%B0%84%20%EB%A9%94%EC%84%9C%EB%93%9C%20%EC%8B%9C%EA%B7%B8%EB%8B%88%EC%B2%98%20%EB%B6%88%EC%9D%BC%EC%B9%98%20%EB%AC%B8%EC%A0%9C%EB%A5%BC%20%EB%B0%94%EB%A1%9C%EC%9E%A1%EC%95%84%20Swagger%20%EB%AC%B8%EC%84%9C%EC%99%80%20%EC%BD%94%EB%93%9C%20%EC%9D%BC%EA%B4%80%EC%84%B1%20%ED%99%95%EB%B3%B4!%20%EC%BD%94%EB%93%9C%20%EC%8B%A0%EB%A2%B0%EB%8F%84%20UP!%20%F0%9F%9A%80%F0%9F%90%87%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94!&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075996)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:10:24Z
author_association: NONE
diff_hunk: @@ -0,0 +1,29 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import jakarta.validation.constraints.*;
+import lombok.Builder;
+
+@Builder
+public record PostCreateRequest(
+
+        @NotBlank(message = "게시글 제목이 비어 있습니다!")
+        @Size(max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        String title,
+
+        @Size(max = 255)
+        String image,
+
+        @NotBlank(message = "본문이 비어 있습니다!")
+        @Size(max = 500, message = "본문의 길이를 1~500자 이내로 작성해 주세요!")
+        String message
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java
user: login: gachaemin
body: @coderabbitai
수정하겠습니다.
created_at: 2025-05-16T00:10:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,29 @@
+package com.playus.communityservice.domain.post.dto.post_create;
+
+import jakarta.validation.constraints.*;
+import lombok.Builder;
+
+@Builder
+public record PostCreateRequest(
+
+        @NotBlank(message = "게시글 제목이 비어 있습니다!")
+        @Size(max = 225, message = "제목의 길이를 1~225자 이내로 작성해 주세요!")
+        String title,
+
+        @Size(max = 255)
+        String image,
+
+        @NotBlank(message = "본문이 비어 있습니다!")
+        @Size(max = 500, message = "본문의 길이를 1~500자 이내로 작성해 주세요!")
+        String message
path: src/main/java/com/playus/communityservice/domain/post/dto/post_create/PostCreateRequest.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 감사합니다! 수정하시는 것에 대해 감사드립니다. 좋은 개발 되세요! 😊

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:10:49Z
author_association: NONE
diff_hunk: @@ -0,0 +1,88 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "ok"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: gachaemin
body: @coderabbitai
수정하겠습니다.
created_at: 2025-05-16T00:11:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,38 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.domain.post.specification.PostControllerSpecification;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController implements PostControllerSpecification {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<String> createPost(@RequestBody @Valid PostCreateRequest request) {
+        postService.createPost(request);
+        return ResponseEntity.ok("{\"ok\"}");
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: gachaemin
body: @coderabbitai
다른 형태를 사용하여 변경하였습니다!
created_at: 2025-05-16T00:11:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,88 @@
+package com.playus.communityservice.domain.post.specification;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.parameters.RequestBody;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.ResponseEntity;
+
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+
+public interface PostControllerSpecification {
+
+    @Tag(name = "Post", description = "게시글 생성 API")
+    @Operation(
+            summary = "게시글 생성",
+            description = "게시글을 작성합니다.",
+            requestBody = @RequestBody(
+                    required = true,
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 요청 예시",
+                                    value = """
+                                    {
+                                      "title": "오늘 경기 재밌었어요!",
+                                      "image": "1",
+                                      "content": "LG가 이길 줄 알았죠!"
+                                    }
+                                    """
+                            )
+                    )
+            )
+    )
+    @ApiResponses(value = {
+            @ApiResponse(
+                    responseCode = "200", description = "생성 성공",
+                    content = @Content(
+                            mediaType = APPLICATION_JSON_VALUE,
+                            examples = @ExampleObject(
+                                    name = "게시글 생성 응답 예시",
+                                    value = """
+                                    {
+                                      "ok"
+                                    }
path: src/main/java/com/playus/communityservice/domain/post/specification/PostControllerSpecification.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 감사합니다! 표준 JSON 형식으로 수정하시면 API 응답의 일관성과 사용성이 향상될 것입니다. 👍

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:11:23Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: @coderabbitai
수정하겠습니다.
created_at: 2025-05-16T00:11:35Z
author_association: CONTRIBUTOR
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: han16935
body: `@PathVariable` 로 받아오는 `tag` 대해서는 어떻게 validate 되나요? 
created_at: 2025-05-16T00:11:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: @gachaemin 감사합니다! 필드 이름의 일관성을 유지하는 것은 코드 가독성과 유지보수성을 높이는 데 큰 도움이 됩니다. 변경해 주셔서 감사합니다.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:11:56Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: @coderabbitai
형식을 통일하게 변경하겠습니다.
created_at: 2025-05-16T00:11:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,38 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.domain.post.specification.PostControllerSpecification;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController implements PostControllerSpecification {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<String> createPost(@RequestBody @Valid PostCreateRequest request) {
+        postService.createPost(request);
+        return ResponseEntity.ok("{\"ok\"}");
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

Let me check how you've implemented the change!

---

🏁 Script executed:
```
#!/bin/bash
# Let's examine the current implementation of PostController class
cat src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
```

Length of output: 2666

---



</details>

@gachaemin 네, 확인했습니다! 단순히 Map을 사용하는 것보다 훨씬 더 좋은 방식으로 구현하셨네요. 다음과 같은 개선사항이 인상적입니다:

1. 각 엔드포인트에 맞는 전용 응답 클래스 사용 (`PostCreateResponse`, `PostUpdateResponse`, `PostDeleteResponse`)
2. 생성 요청에 대해 201 Created 상태코드와 Location 헤더 추가
3. `@AuthenticationPrincipal`을 통한 인증 처리
4. 명확한 메서드 시그니처와 반환 타입

이런 방식이 RESTful API 설계 관점에서 훨씬 더 명확하고 견고합니다. 좋은 개선이었습니다! 👍

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%20JSON%20%EC%9D%91%EB%8B%B5%EC%9D%84%20%ED%95%98%EB%93%9C%EC%BD%94%EB%94%A9%20%EB%AC%B8%EC%9E%90%EC%97%B4%20%EB%8C%80%EC%8B%A0%20%EA%B0%9D%EC%B2%B4%EB%A1%9C%20%EB%B0%98%ED%99%98%ED%95%B4%EB%B3%B4%EC%84%B8%EC%9A%94!%20Spring%EC%9D%B4%20%EC%9E%90%EB%8F%99%EC%9C%BC%EB%A1%9C%20%EC%A7%81%EB%A0%AC%ED%99%94%ED%95%B4%20%EC%BD%94%EB%93%9C%20%EA%B0%84%EA%B2%B0%EC%84%B1%EA%B3%BC%20%EC%9C%A0%EC%A7%80%EB%B3%B4%EC%88%98%EC%84%B1%20UP!%20%F0%9F%9B%A0%EF%B8%8F%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94!&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2083848741)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:11:59Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글입니다.");
+        }
+
+        post.delete();
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: @coderabbitai
파일 전체를 수정하였습니다.
created_at: 2025-05-16T00:12:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 좋습니다! 오류 메시지 형식을 통일하면 코드의 일관성이 향상될 것입니다. 변경해 주셔서 감사합니다.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:12:16Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글입니다.");
+        }
+
+        post.delete();
+    }
+
+    @Transactional
+    public PostUpdateResponse updatePost(PostUpdateRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글은 수정할 수 없습니다.");
+        }
+
+        post.updateAll(
+                request.title(),
+                request.content(),
+                Tag.LG_TWINS, // 임시로 태그는 고정 처리
+                false         // isSecret도 false 고정 처리
+        );
+
+        return PostUpdateResponse.ok();
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: @coderabbitai
위와 같이 수정하였습니다.
created_at: 2025-05-16T00:12:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글입니다.");
+        }
+
+        post.delete();
+    }
+
+    @Transactional
+    public PostUpdateResponse updatePost(PostUpdateRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글은 수정할 수 없습니다.");
+        }
+
+        post.updateAll(
+                request.title(),
+                request.content(),
+                Tag.LG_TWINS, // 임시로 태그는 고정 처리
+                false         // isSecret도 false 고정 처리
+        );
+
+        return PostUpdateResponse.ok();
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: @gachaemin 수정 사항 반영해 주셔서 감사합니다! 권한 검사와 예외 메시지 개선이 잘 적용되었네요. 추가 질문이나 도움이 필요한 사항이 있으시면 언제든지 말씀해 주세요.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:12:44Z
author_association: NONE
diff_hunk: @@ -0,0 +1,86 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.file.entity.File;
+import com.playus.communityservice.domain.file.repository.write.FileRepository;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.entity.PostImage;
+import com.playus.communityservice.domain.post.enums.Tag;
+import com.playus.communityservice.domain.post.repository.write.PostImageRepository;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+    private final FileRepository fileRepository;
+    private final PostImageRepository postImageRepository;
+
+    @Transactional
+    public void createPost(PostCreateRequest request) {
+        // 기본값 지정
+        Long writerId = 1L; // 나중에 인증 연동 시 대체
+        Tag defaultTag = Tag.LG_TWINS; // 기본 태그 (클라이언트가 안 보내니까 서버에서 결정)
+
+        // Post 생성 및 저장
+        Post post = Post.create(
+                writerId,
+                request.title(),
+                request.message(),
+                defaultTag
+        );
+        post = postRepository.save(post);
+
+        // image 필드가 있으면 PostImage로 연결
+        if (request.image() != null && !request.image().isBlank()) {
+            try {
+                Long fileId = Long.parseLong(request.image());
+                File file = fileRepository.findById(fileId)
+                        .orElseThrow(() -> new IllegalArgumentException("File not found with id = " + fileId));
+                PostImage postImage = PostImage.create(post, file);
+                postImageRepository.save(postImage);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Image field must be a valid numeric string (file ID)");
+            }
+        }
+    }
+
+    @Transactional
+    public void deletePost(PostDeleteRequest request) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new IllegalArgumentException("Post not found with id = " + request.postId()));
+
+        if (!post.isActivated()) {
+            throw new IllegalStateException("이미 삭제된 게시글입니다.");
+        }
+
+        post.delete();
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: <details>
<summary>🧩 Analysis chain</summary>

The script execution has completed. Let's review the results:



@gachaemin 파일 전체를 확인했습니다. PostService 클래스를 완전히 개선하셨네요! JwtUser를 통한 인증 통합, EntityNotFoundException과 UnauthorizedAccessException을 활용한 적절한 예외 처리, 그리고 모든 메소드(createPost, updatePost, deletePost)에 대한 완전한 구현이 이루어졌습니다. 이전 버전보다 훨씬 견고하고 체계적으로 개선되었습니다. 좋은 작업이었습니다! 👍

(\_/)<br>
(•ᴗ•)<br>
/ >📝

---

🏁 Script executed:
```
#!/bin/bash
# Check if the file exists and display its current content
cat src/main/java/com/playus/communityservice/domain/post/service/PostService.java
```

Length of output: 2668

---



</details>

@gachaemin 파일 전체를 확인했습니다. PostService 클래스가 완전히 개선되었네요! 다음과 같은 좋은 변화들이 보입니다:

1. JwtUser를 통한 적절한 인증 통합
2. EntityNotFoundException과 UnauthorizedAccessException을 활용한 명확한 예외 처리
3. 각 메소드(createPost, updatePost, deletePost)에 대한 적절한 응답 객체 반환
4. 모든 메소드에 트랜잭션 처리 적용
5. 일관된 한글 메시지 사용

이전 버전보다 훨씬 견고하고 체계적으로 개선되었습니다. 좋은 작업이었습니다! 👍

(\_/)<br>
(•ᴗ•)<br>
/ >📝

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:12:56Z
author_association: NONE
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: gachaemin
body: 요청된 URL의 String값이 Enum에 있는 teamName과 일치할 경우 자동으로 매핑되고, 일치하지 않으면 MethodArgumentTypeMismatchException을 발생시키도록 하였습니다.
created_at: 2025-05-16T00:20:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,42 @@
+package com.playus.communityservice.global.config.jwt;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+@Getter
+@AllArgsConstructor
+public class JwtUser implements UserDetails {
+    private final Long userId;
+    private final String role;
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return null;
+    }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java
user: login: gachaemin
body: @coderabbitai
role자체가 많이 중요하지 않아서 null로 비워놨습니다.
created_at: 2025-05-16T00:27:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,42 @@
+package com.playus.communityservice.global.config.jwt;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.Collection;
+
+@Getter
+@AllArgsConstructor
+public class JwtUser implements UserDetails {
+    private final Long userId;
+    private final String role;
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return null;
+    }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java
user: login: coderabbitai[bot]
body: @gachaemin 이해했습니다. 만약 프로젝트에서 role을 사용한 권한 체크를 하지 않는다면 `null`로 두어도 문제가 없을 수 있습니다. 설명해주셔서 감사합니다.



/|\\_/|\\
(o.o)
(> ^ <)

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: gachaemin
PR: KEA-ChunSam/PlayUs-community-service#23
File: src/main/java/com/playus/communityservice/global/config/jwt/JwtUser.java:17-19
Timestamp: 2025-05-16T00:28:10.574Z
Learning: 이 프로젝트에서는 JwtUser의 role 필드가 중요하지 않아 getAuthorities() 메서드가 null을 반환하도록 구현되어 있음.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:28:11Z
author_association: NONE
diff_hunk: @@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
+
+        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+        if (header != null && header.startsWith("Bearer ")) {
+            String token = header.substring(7);
+            try {
+                if (!jwtUtil.isExpired(token)) {
+                    Long userId = Long.parseLong(jwtUtil.getUserId(token));
+                    String role = jwtUtil.getRole(token);
+
+                    JwtUser jwtUser = new JwtUser(userId, role);
+                    Authentication auth = new UsernamePasswordAuthenticationToken(
+                            jwtUser, null, jwtUser.getAuthorities()
+                    );
+                    SecurityContextHolder.getContext().setAuthentication(auth);
+                }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
user: login: gachaemin
body: @coderabbitai
수정하겠습니다.
created_at: 2025-05-16T00:28:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
+
+        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+        if (header != null && header.startsWith("Bearer ")) {
+            String token = header.substring(7);
+            try {
+                if (!jwtUtil.isExpired(token)) {
+                    Long userId = Long.parseLong(jwtUtil.getUserId(token));
+                    String role = jwtUtil.getRole(token);
+
+                    JwtUser jwtUser = new JwtUser(userId, role);
+                    Authentication auth = new UsernamePasswordAuthenticationToken(
+                            jwtUser, null, jwtUser.getAuthorities()
+                    );
+                    SecurityContextHolder.getContext().setAuthentication(auth);
+                }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
user: login: coderabbitai[bot]
body: @gachaemin 감사합니다! 변경사항을 적용해 주시면 인증 처리가 더 견고해질 것입니다. 도움이 필요하시면 언제든지 말씀해 주세요. 

(∩^ω^)⊃━☆ﾟ.*･｡ﾟ

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:28:52Z
author_association: NONE
diff_hunk: @@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
+
+        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+        if (header != null && header.startsWith("Bearer ")) {
+            String token = header.substring(7);
+            try {
+                if (!jwtUtil.isExpired(token)) {
+                    Long userId = Long.parseLong(jwtUtil.getUserId(token));
+                    String role = jwtUtil.getRole(token);
+
+                    JwtUser jwtUser = new JwtUser(userId, role);
+                    Authentication auth = new UsernamePasswordAuthenticationToken(
+                            jwtUser, null, jwtUser.getAuthorities()
+                    );
+                    SecurityContextHolder.getContext().setAuthentication(auth);
+                }
+            } catch (JwtException | IllegalArgumentException e) {
+                log.debug("JWT 인증 실패: {}", e.getMessage());
+            }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
user: login: gachaemin
body: @coderabbitai
이 부분은 이후 추가로 수정할 예정입니다.
created_at: 2025-05-16T00:29:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,57 @@
+package com.playus.communityservice.global.config.jwt;
+
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import io.jsonwebtoken.JwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import java.io.IOException;
+
+@Slf4j
+@Component
+public class JwtFilter extends OncePerRequestFilter {
+
+    private final JwtUtil jwtUtil;
+
+    public JwtFilter(JwtUtil jwtUtil) {
+        this.jwtUtil = jwtUtil;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request,
+                                    HttpServletResponse response,
+                                    FilterChain chain)
+            throws ServletException, IOException {
+
+        String header = request.getHeader(HttpHeaders.AUTHORIZATION);
+
+        if (header != null && header.startsWith("Bearer ")) {
+            String token = header.substring(7);
+            try {
+                if (!jwtUtil.isExpired(token)) {
+                    Long userId = Long.parseLong(jwtUtil.getUserId(token));
+                    String role = jwtUtil.getRole(token);
+
+                    JwtUser jwtUser = new JwtUser(userId, role);
+                    Authentication auth = new UsernamePasswordAuthenticationToken(
+                            jwtUser, null, jwtUser.getAuthorities()
+                    );
+                    SecurityContextHolder.getContext().setAuthentication(auth);
+                }
+            } catch (JwtException | IllegalArgumentException e) {
+                log.debug("JWT 인증 실패: {}", e.getMessage());
+            }
path: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 이해했습니다. 추후에 해당 부분을 수정하실 계획이신 것으로 확인했습니다. 필요한 시점에 업데이트하시면 됩니다. 👍

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: gachaemin
PR: KEA-ChunSam/PlayUs-community-service#23
File: src/main/java/com/playus/communityservice/global/config/jwt/JwtFilter.java:50-52
Timestamp: 2025-05-16T00:29:40.571Z
Learning: JWT 인증 실패 예외 처리는 PlayUs-community-service 프로젝트에서 이후에 수정할 예정인 사항입니다.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:29:41Z
author_association: NONE
diff_hunk: @@ -0,0 +1,58 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import com.playus.communityservice.global.exception.EntityNotFoundException;
+import com.playus.communityservice.global.exception.UnauthorizedAccessException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+
+    @Transactional
+    public PostCreateResponse createPost(PostCreateRequest request, JwtUser user, TeamTag tag) {
+        Post post = Post.create(user.getId(), request.title(), request.content(), tag, request.jwpDate());
+        postRepository.save(post);
+
+        return PostCreateResponse.of(post.getId(), "게시물 생성이 완료되었습니다.");
+    }
+
+    @Transactional
+    public PostUpdateResponse updatePost(PostUpdateRequest request, JwtUser user, TeamTag tag) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new EntityNotFoundException("게시글"));
+
+        if (!post.getWriterId().equals(user.getId())) {
+            throw new UnauthorizedAccessException("게시글");
+        }
+
+        post.updateAll(request.title(), request.content(), TeamTag.DOOSAN_BEARS, false, request.jwpDate());
+        return PostUpdateResponse.fo(true, "게시물이 수정되었습니다.");
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: gachaemin
body: @coderabbitai
수정하겠습니다.
created_at: 2025-05-16T00:31:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+package com.playus.communityservice.domain.post.service;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.entity.Post;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.repository.write.PostRepository;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import com.playus.communityservice.global.exception.EntityNotFoundException;
+import com.playus.communityservice.global.exception.UnauthorizedAccessException;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@RequiredArgsConstructor
+public class PostService {
+
+    private final PostRepository postRepository;
+
+    @Transactional
+    public PostCreateResponse createPost(PostCreateRequest request, JwtUser user, TeamTag tag) {
+        Post post = Post.create(user.getId(), request.title(), request.content(), tag, request.jwpDate());
+        postRepository.save(post);
+
+        return PostCreateResponse.of(post.getId(), "게시물 생성이 완료되었습니다.");
+    }
+
+    @Transactional
+    public PostUpdateResponse updatePost(PostUpdateRequest request, JwtUser user, TeamTag tag) {
+        Post post = postRepository.findById(request.postId())
+                .orElseThrow(() -> new EntityNotFoundException("게시글"));
+
+        if (!post.getWriterId().equals(user.getId())) {
+            throw new UnauthorizedAccessException("게시글");
+        }
+
+        post.updateAll(request.title(), request.content(), TeamTag.DOOSAN_BEARS, false, request.jwpDate());
+        return PostUpdateResponse.fo(true, "게시물이 수정되었습니다.");
+    }
path: src/main/java/com/playus/communityservice/domain/post/service/PostService.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 이해했습니다. 수정을 진행해 주셔서 감사합니다!

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40coderabbitai%EA%B0%80%20%EC%A7%80%EC%A0%81%ED%95%9C%20%ED%95%98%EB%93%9C%EC%BD%94%EB%94%A9%20%EB%AC%B8%EC%A0%9C%20%ED%95%B4%EA%B2%B0!%20TeamTag%EC%99%80%20isSecret%20%EA%B0%92%EC%9D%84%20%EB%8F%99%EC%A0%81%EC%9C%BC%EB%A1%9C%20%EC%B2%98%EB%A6%AC%ED%95%98%EA%B3%A0%2C%20%EC%9D%91%EB%8B%B5%20%EB%A9%94%EC%84%9C%EB%93%9C%20%EC%98%A4%ED%83%80%EB%8F%84%20%EC%88%98%EC%A0%95%ED%95%B4%20%EC%BD%94%EB%93%9C%20%EC%9C%A0%EC%97%B0%EC%84%B1%EA%B3%BC%20%EC%95%88%EC%A0%95%EC%84%B1%20UP!%20%F0%9F%9A%80%20%EA%BC%AD%20%EC%8D%A8%EB%B3%B4%EC%84%B8%EC%9A%94!&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075976)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:31:51Z
author_association: NONE
diff_hunk: @@ -0,0 +1,50 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<PostCreateResponse> create(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostCreateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostCreateResponse response = postService.createPost(request, user, tag);
+        URI location = URI.create("/post/" + response.postId());
+        return ResponseEntity.created(location).body(response);
+    }
+
+    @PatchMapping
+    public ResponseEntity<PostUpdateResponse> update(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostUpdateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostUpdateResponse response = postService.updatePost(request, user, tag);
+        return ResponseEntity.ok(response);
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: gachaemin
body: @coderabbitai
바로 반영하겠습니다.
created_at: 2025-05-16T00:32:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,50 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<PostCreateResponse> create(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostCreateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostCreateResponse response = postService.createPost(request, user, tag);
+        URI location = URI.create("/post/" + response.postId());
+        return ResponseEntity.created(location).body(response);
+    }
+
+    @PatchMapping
+    public ResponseEntity<PostUpdateResponse> update(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostUpdateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostUpdateResponse response = postService.updatePost(request, user, tag);
+        return ResponseEntity.ok(response);
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 감사합니다! 수정사항이 반영되면 경로 변수가 올바르게 바인딩될 것입니다. 👍

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:33:18Z
author_association: NONE
diff_hunk: @@ -0,0 +1,50 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<PostCreateResponse> create(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostCreateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostCreateResponse response = postService.createPost(request, user, tag);
+        URI location = URI.create("/post/" + response.postId());
+        return ResponseEntity.created(location).body(response);
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: gachaemin
body: @coderabbitai
바로 반영하겠습니다.
created_at: 2025-05-16T00:33:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,50 @@
+package com.playus.communityservice.domain.post.controller;
+
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateRequest;
+import com.playus.communityservice.domain.post.dto.post_create.PostCreateResponse;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteRequest;
+import com.playus.communityservice.domain.post.dto.post_delete.PostDeleteResponse;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateRequest;
+import com.playus.communityservice.domain.post.dto.post_update.PostUpdateResponse;
+import com.playus.communityservice.domain.post.enums.TeamTag;
+import com.playus.communityservice.domain.post.service.PostService;
+import com.playus.communityservice.global.config.jwt.JwtUser;
+import jakarta.validation.Valid;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.annotation.AuthenticationPrincipal;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+
+@RestController
+@RequestMapping("/post")
+@RequiredArgsConstructor
+public class PostController {
+
+    private final PostService postService;
+
+    @PostMapping
+    public ResponseEntity<PostCreateResponse> create(@PathVariable TeamTag tag,
+                                                     @Valid @RequestBody PostCreateRequest request,
+                                                     @AuthenticationPrincipal JwtUser user) {
+        PostCreateResponse response = postService.createPost(request, user, tag);
+        URI location = URI.create("/post/" + response.postId());
+        return ResponseEntity.created(location).body(response);
+    }
path: src/main/java/com/playus/communityservice/domain/post/controller/PostController.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 감사합니다! 빠른 조치에 감사드립니다. 수정 후 API가 올바르게 작동할 것입니다. 👍

---

<!-- This is an auto-generated comment: tweet message by coderabbit.ai -->

If you found this review helpful, would you consider giving us a shout-out on [X](https://twitter.com/intent/tweet?related=CodeRabbitAI&text=%40PostMapping%EC%97%90%20%EA%B2%BD%EB%A1%9C%20%EB%B3%80%EC%88%98%20%EB%88%84%EB%9D%BD%20%EC%8B%9C%20%EB%9F%B0%ED%83%80%EC%9E%84%20%EC%98%A4%EB%A5%98%20%EB%B0%9C%EC%83%9D!%20%EB%A9%94%EC%84%9C%EB%93%9C%20%EC%8B%9C%EA%B7%B8%EB%8B%88%EC%B2%98%EC%99%80%20%EB%A7%A4%EC%B9%AD%EB%90%98%EB%8A%94%20%EA%B2%BD%EB%A1%9C%20%ED%85%9C%ED%94%8C%EB%A6%BF%20%EA%BC%AD%20%EC%B6%94%EA%B0%80%ED%95%98%EC%84%B8%EC%9A%94.%20%40coderabbitai%20%EB%8D%95%EB%B6%84%EC%97%90%20%EC%8B%A4%EC%88%98%20%EB%B0%A9%EC%A7%80%20%EC%99%84%EB%A3%8C!%20%F0%9F%9A%80%F0%9F%90%87&url=https%3A%2F%2Fgithub.com%2FKEA-ChunSam%2FPlayUs-community-service%2Fpull%2F23%23discussion_r2090075981)?

Thank you for using CodeRabbit!

<!-- end of auto-generated comment: tweet message by coderabbit.ai -->



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:33:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,64 @@
+package com.playus.communityservice.global.exception;
+
+import com.playus.communityservice.domain.post.controller.PostController;
+import com.playus.communityservice.global.response.ErrorResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.server.ResponseStatusException;
+
+
+@Slf4j
+@RestControllerAdvice(assignableTypes = {
+        PostController.class
+})
+public class ExceptionAdvice {
+
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<String> bindExceptionHandler(BindException e) {
+        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
+        log.warn("Validation Error: {}", errorMessage);
+        return ResponseEntity.badRequest().body(errorMessage);
+    }
path: src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
user: login: gachaemin
body: @coderabbitai
수정하도록 하겠습니다.
created_at: 2025-05-16T00:35:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,64 @@
+package com.playus.communityservice.global.exception;
+
+import com.playus.communityservice.domain.post.controller.PostController;
+import com.playus.communityservice.global.response.ErrorResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.server.ResponseStatusException;
+
+
+@Slf4j
+@RestControllerAdvice(assignableTypes = {
+        PostController.class
+})
+public class ExceptionAdvice {
+
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<String> bindExceptionHandler(BindException e) {
+        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
+        log.warn("Validation Error: {}", errorMessage);
+        return ResponseEntity.badRequest().body(errorMessage);
+    }
path: src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 감사합니다! 응답 형식의 일관성을 유지해주시면 API 사용자들에게 더 나은 경험을 제공할 수 있을 것입니다. 수정 후 API 응답이 모두 동일한 형식을 가지게 되어 클라이언트 측에서 오류 처리가 더 쉬워질 것입니다.

<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:35:42Z
author_association: NONE
diff_hunk: @@ -0,0 +1,64 @@
+package com.playus.communityservice.global.exception;
+
+import com.playus.communityservice.domain.post.controller.PostController;
+import com.playus.communityservice.global.response.ErrorResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.server.ResponseStatusException;
+
+
+@Slf4j
+@RestControllerAdvice(assignableTypes = {
+        PostController.class
+})
+public class ExceptionAdvice {
+
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<String> bindExceptionHandler(BindException e) {
+        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
+        log.warn("Validation Error: {}", errorMessage);
+        return ResponseEntity.badRequest().body(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.UNAUTHORIZED)
+    @ExceptionHandler(ResponseStatusException.class)
+    public ErrorResponse responseStatusExHandler(ResponseStatusException e) {
+        String errorMessage = e.getMessage();
+        log.warn("INVALID_TOKEN Error: {}", errorMessage);
+        return ErrorResponse.unauthorizedError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.NOT_FOUND)
+    @ExceptionHandler({
+            EntityNotFoundException.class
+    })
+    public ErrorResponse handleEntityNotFoundException(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Entity Not Found Error: {}", errorMessage);
+        return ErrorResponse.notFoundError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.FORBIDDEN)
+    @ExceptionHandler({
+            UnauthorizedAccessException.class
+    })
+    public ErrorResponse handleUnauthorizedAccessException(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Unauthorized Access Error: {}", errorMessage);
+        return ErrorResponse.forbiddenError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    @ExceptionHandler(Exception.class)
+    public ResponseEntity<String> otherExceptionHandler(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Unexpected Error: {}", errorMessage);
+        return ResponseEntity.internalServerError().body("서버 에러가 발생했습니다! 관리자에게 문의해 주세요!");
+    }
path: src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
user: login: gachaemin
body: @coderabbitai
수정하겠습니다.
created_at: 2025-05-16T00:37:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,64 @@
+package com.playus.communityservice.global.exception;
+
+import com.playus.communityservice.domain.post.controller.PostController;
+import com.playus.communityservice.global.response.ErrorResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.BindException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.server.ResponseStatusException;
+
+
+@Slf4j
+@RestControllerAdvice(assignableTypes = {
+        PostController.class
+})
+public class ExceptionAdvice {
+
+    @ResponseStatus(HttpStatus.BAD_REQUEST)
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<String> bindExceptionHandler(BindException e) {
+        String errorMessage = e.getAllErrors().get(0).getDefaultMessage();
+        log.warn("Validation Error: {}", errorMessage);
+        return ResponseEntity.badRequest().body(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.UNAUTHORIZED)
+    @ExceptionHandler(ResponseStatusException.class)
+    public ErrorResponse responseStatusExHandler(ResponseStatusException e) {
+        String errorMessage = e.getMessage();
+        log.warn("INVALID_TOKEN Error: {}", errorMessage);
+        return ErrorResponse.unauthorizedError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.NOT_FOUND)
+    @ExceptionHandler({
+            EntityNotFoundException.class
+    })
+    public ErrorResponse handleEntityNotFoundException(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Entity Not Found Error: {}", errorMessage);
+        return ErrorResponse.notFoundError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.FORBIDDEN)
+    @ExceptionHandler({
+            UnauthorizedAccessException.class
+    })
+    public ErrorResponse handleUnauthorizedAccessException(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Unauthorized Access Error: {}", errorMessage);
+        return ErrorResponse.forbiddenError(errorMessage);
+    }
+
+    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
+    @ExceptionHandler(Exception.class)
+    public ResponseEntity<String> otherExceptionHandler(Exception e) {
+        String errorMessage = e.getMessage();
+        log.error("Unexpected Error: {}", errorMessage);
+        return ResponseEntity.internalServerError().body("서버 에러가 발생했습니다! 관리자에게 문의해 주세요!");
+    }
path: src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
user: login: coderabbitai[bot]
body: @gachaemin 네, 수정에 동의해 주셔서 감사합니다! 말씀하신 대로 반환 형식을 일관성 있게 변경하시면 됩니다. `ErrorResponse` 클래스에 `serverError` 메서드가 아직 없다면, 다른 에러 메서드와 유사하게 추가해 주시길 바랍니다.

코드 일관성을 유지하기 위한 노력에 감사드립니다! 👍



```
(\u2114 ᴗ \u2114)
        \\
```

---

<details>
<summary>✏️ Learnings added</summary>

```
Learnt from: gachaemin
PR: KEA-ChunSam/PlayUs-community-service#23
File: src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java:57-63
Timestamp: 2025-05-16T00:37:32.072Z
Learning: ExceptionAdvice 클래스에서 모든 예외 핸들러 메서드는 일관된 형식의 ErrorResponse 객체를 반환해야 합니다.
```

> Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure [review instructions](https://docs.coderabbit.ai/guides/review-instructions). You can manage existing learnings in the [app](https://app.coderabbit.ai/learnings).

</details>



<!-- This is an auto-generated reply by CodeRabbit -->
created_at: 2025-05-16T00:37:33Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-12T05:30:00Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

"""
## Walkthrough

커뮤니티 서비스의 게시글(Post) 관련 API를 구현하는 새로운 컨트롤러, 서비스, DTO, 스펙 인터페이스, 저장소가 추가되었습니다. 게시글 생성, 삭제, 수정의 엔드포인트와 그에 필요한 데이터 구조 및 서비스 로직이 도입되었습니다.

## Changes

| 파일/경로 요약 | 변경 요약 |
|---|---|
| .../controller/PostController.java, .../specification/PostControllerSpecification.java | 게시글 생성/삭제/수정 REST API 컨트롤러 및 스펙 인터페이스 추가, OpenAPI 문서화 |
| .../dto/post_create/PostCreateRequest.java, .../dto/post_create/PostCreateResponse.java, .../dto/post_delete/PostDeleteRequest.java, .../dto/post_delete/PostDeleteResponse.java, .../dto/post_update/PostUpdateRequest.java, .../dto/post_update/PostUpdateResponse.java | 게시글 생성/삭제/수정 요청 및 응답 DTO 레코드 클래스 및 정적 팩토리 메서드 추가, 유효성 검사 어노테이션 적용 |
| .../service/PostService.java | 게시글 생성, 삭제, 수정 서비스 로직 및 트랜잭션 처리 추가, 예외 처리 포함 |
| .../repository/write/PostImageRepository.java | PostImage 엔티티용 JPA 저장소 인터페이스 추가 |
| .../domain/post/document/PostDocument.java, .../domain/post/entity/Post.java | 기존 Tag enum 삭제 후 TeamTag enum으로 변경, jwpDate 필드 추가 및 관련 생성자/메서드 수정 |
| .../domain/post/enums/Tag.java | 기존 Tag enum 삭제 |
| .../domain/post/enums/TeamTag.java | 새로운 TeamTag enum 추가, 문자열 기반 변환 메서드 포함 |
| .../global/config/jwt/JwtFilter.java, JwtUser.java, JwtUtil.java | JWT 인증 필터, 사용자 정보, 토큰 생성 및 검증 유틸리티 추가 |
| .../global/config/security/CorsConfig.java, SecurityConfig.java | CORS 설정 및 Spring Security 설정 추가, JWT 필터 적용 및 Swagger 허용 설정 포함 |
| .../global/exception/EntityNotFoundException.java, UnauthorizedAccessException.java, ExceptionAdvice.java | 커스텀 예외 및 전역 예외 처리 핸들러 추가 |
| .../global/response/ErrorResponse.java | 표준화된 에러 응답 DTO 레코드 및 정적 팩토리 메서드 추가 |
| CommunityServiceApplication.java | Redis 자동 설정 제외 설정 추가 |
| application-local.yaml | 외부 .env 프로퍼티 파일 선택적 로드 설정 추가 |
| build.gradle | WebSocket, Security, JWT, Apache Commons Lang3 등 의존성 추가 |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant PostController
    participant PostService
    participant PostRepository
    participant FileRepository
    participant PostImageRepository

    Client->>PostController: POST /post (PostCreateRequest)
    PostController->>PostService: createPost(request, user, tag)
    PostService->>PostRepository: save(Post)
    alt 이미지 ID 존재
        PostService->>FileRepository: findById(imageId)
        PostService->>PostImageRepository: save(PostImage)
    end
    PostService-->>PostController: PostCreateResponse
    PostController-->>Client: 201 Created (Location header + PostCreateResponse)

    Client->>PostController: PATCH /post (PostUpdateRequest)
    PostController->>PostService: updatePost(request, user, tag)
    PostService->>PostRepository: findById(postId)
    PostService->>PostService: 권한 확인
    PostService-->>PostRepository: post.update(...)
    PostService-->>PostController: PostUpdateResponse
    PostController-->>Client: 200 OK (PostUpdateResponse)

    Client->>PostController: DELETE /post (PostDeleteRequest)
    PostController->>PostService: deletePost(request, user)
    PostService->>PostRepository: findById(postId)
    PostService->>PostService: 권한 확인
    PostService-->>PostRepository: post.delete()
    PostService-->>PostController: PostDeleteResponse
    PostController-->>Client: 200 OK (PostDeleteResponse)
```

## Assessment against linked issues

| Objective (이슈 번호) | Addressed | Explanation |
|---|---|---|
| 커뮤니티 글에 관련된 API 구현 (#22) | ✅ |  |

## Suggested reviewers

- yoonjiseok

## Poem

> 코드를 심는 토끼가 말해요,  
> 게시글 API가 새로 솟아나요!  
> 생성, 삭제, 수정까지 척척,  
> DTO와 서비스가 한데 모여 똑딱!  
> 커뮤니티 정원에 꽃이 피었네,  
> 🥕🐰 오늘도 코드는 평화롭네!
"""

</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!NOTE]
> <details>
> <summary>⚡️ AI Code Reviews for VS Code, Cursor, Windsurf</summary>
> 
> CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
> Learn more [here](http://coderabbit.ai/ide).
> 
> </details>

---

> [!NOTE]
> <details>
> <summary>⚡️ Faster reviews with caching</summary>
> 
> CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure `Review - Disable Cache` at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the `Data Retention` setting under your Organization Settings.
> Enjoy the performance boost—your workflow just got faster.
> 
> </details>

<!-- announcements_end -->

---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Lite**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 19cb93526cbbda48c5f3d201babd28c295ea1b61 and c113a37f39708cb3a538dc9e746bde8d63e042cc.

</details>

<details>
<summary>📒 Files selected for processing (3)</summary>

* `src/main/java/com/playus/communityservice/domain/post/controller/PostController.java` (1 hunks)
* `src/main/java/com/playus/communityservice/domain/post/service/PostService.java` (1 hunks)
* `src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (3)</summary>

* src/main/java/com/playus/communityservice/global/exception/ExceptionAdvice.java
* src/main/java/com/playus/communityservice/domain/post/service/PostService.java
* src/main/java/com/playus/communityservice/domain/post/controller/PostController.java

</details>

</details>
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=KEA-ChunSam/PlayUs-community-service&utm_content=23):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-12T05:30:59Z
body: ## Test Results
1 tests   1 ✅  0s ⏱️
1 suites  0 💤
1 files    0 ❌

Results for commit c113a37f.

[test-results]:data:application/gzip;base64,H4sIAPGKJmgC/1WNyw7CIBBFf6Vh7QKcWqg/09ABkoltMTxWxn8X0Srd3XPv5MyDOVpsZNdOnDoWM6UfmBx0Ir8V5AXLkPap5ilmxGNxo3t7PTlNy6GwIfjwbULedt87troP/22VG1nl1oV+XSkVYCgEaJAORskVzqAvoAyOVvbDbKwyA1jen8un5wtMk1B2+wAAAA==

:recycle: This comment has been updated with latest results.
author_association: NONE