Skip to content

feat: 비로그인 사용자를 위한 공개 게시글 조회 API 구현#133

Merged
yooooonshine merged 3 commits intodevelopfrom
modic_backend_130
Aug 24, 2025
Merged

feat: 비로그인 사용자를 위한 공개 게시글 조회 API 구현#133
yooooonshine merged 3 commits intodevelopfrom
modic_backend_130

Conversation

@goalSetter09
Copy link
Collaborator

@goalSetter09 goalSetter09 commented Aug 10, 2025

Summary

Closes #130

GitHub Issue #130을 해결하기 위해 비로그인 사용자도 게시글을 조회할 수 있는 공개 API를 구현했습니다.

  • 새로운 엔드포인트: /api/public/posts/{id} GET 요청
  • 기존 API 유지: /api/posts/{id} - 로그인된 사용자용 (좋아요 정보 포함)
  • 공개 API 특징: 비로그인 사용자용 (좋아요 정보는 false로 고정)

구현 내용

Backend Changes

  • PublicPostController: 비로그인 사용자를 위한 새로운 컨트롤러 생성
  • PostService.getPostForPublic(): 인증 없는 게시글 조회 메서드 추가
  • 동일한 응답 구조: 기존 GetPostResponse DTO 재사용

주요 차이점

기능 기존 API (/api/posts/{id}) 새 공개 API (/api/public/posts/{id})
인증 필수 (JWT 토큰) 불필요
좋아요 정보 사용자별 실제 값 (true/false) 고정값 (false)
사용 대상 로그인된 사용자 모든 사용자 (비로그인 포함)

Test Plan

  • PostService.getPostForPublic() 단위 테스트
    • 정상 조회 시 게시글 정보 반환 및 isLikedByCurrentUser = false 확인
    • 존재하지 않는 게시글 ID로 조회 시 예외 발생 확인
    • PostLikeService.isLikedByUser() 메서드 호출되지 않음 확인
  • PublicPostController 통합 테스트
    • GET /api/public/posts/{id} 정상 응답 확인
    • 존재하지 않는 게시글 조회 시 404 응답 확인
    • 잘못된 경로 파라미터 시 400 응답 확인
  • 모든 테스트 통과 확인

추가 작업 필요

사용자는 application.yml에 다음 설정을 추가해야 합니다:

security:
  permit-urls:
    - GET:/api/public/posts/**

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 신규 기능

    • 비로그인(공개) 사용자가 게시글을 조회할 수 있는 공개 게시글 조회 API가 추가되었습니다.
  • 테스트

    • 공개 게시글 조회 서비스 및 컨트롤러에 대한 단위 테스트와 통합 테스트가 추가되었습니다.
    • 정상 조회, 존재하지 않는 게시글 요청, 잘못된 경로 파라미터 등 다양한 케이스가 검증됩니다.

goalSetter09 and others added 2 commits August 10, 2025 17:58
- PublicPostController: /api/public/posts/{id} 엔드포인트 구현
- PostService.getPostForPublic(): 인증 없는 게시글 조회 메서드 추가
- 비로그인 사용자도 게시글 정보 조회 가능 (좋아요 상태는 false로 설정)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- PostServiceTest: getPostForPublic 메서드 단위 테스트 추가
- PublicPostControllerTest: 공개 게시글 조회 API 통합 테스트 추가
- 정상 조회, 예외 상황, 잘못된 파라미터 케이스 테스트 커버

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Aug 10, 2025

Walkthrough

비로그인(공개) 사용자가 게시글을 조회할 수 있도록, 새로운 공개용 게시글 조회 서비스 메서드와 REST API 엔드포인트가 추가되었습니다. 이에 대한 서비스 로직, 컨트롤러, 그리고 단위 및 통합 테스트가 함께 구현되었습니다.

Changes

Cohort / File(s) Change Summary
공개 게시글 조회 서비스 로직
src/main/java/hanium/modic/backend/domain/post/service/PostService.java
비로그인 사용자를 위한 getPostForPublic(Long id) 메서드 추가. 게시글, 작성자, 이미지, 좋아요 수를 조회하며, liked 상태는 항상 false로 반환.
공개 게시글 조회 컨트롤러
src/main/java/hanium/modic/backend/web/post/controller/PublicPostController.java
/api/public/posts/{id} GET 엔드포인트 제공하는 PublicPostController 신설. 서비스의 공개 조회 메서드 호출 후 결과 반환. OpenAPI 문서화 및 예외 응답 처리 포함.
서비스 계층 테스트
src/test/java/hanium/modic/backend/domain/post/service/PostServiceTest.java
getPostForPublic 메서드 정상/예외 상황 단위 테스트 추가. 좋아요 상태, 예외 발생 시 서비스 메서드 호출 여부 검증.
컨트롤러 계층 테스트
src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java
PublicPostController의 공개 게시글 조회 API에 대한 MockMvc 기반 통합 테스트 클래스 신설. 정상/404/400 상황별 응답 검증.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant PublicPostController
    participant PostService
    participant PostRepository
    participant PostLikeService

    Client->>PublicPostController: GET /api/public/posts/{id}
    PublicPostController->>PostService: getPostForPublic(id)
    PostService->>PostRepository: findById(id)
    PostService->>PostLikeService: getLikeCount(id)
    PostService-->>PublicPostController: GetPostResponse (liked=false)
    PublicPostController-->>Client: 200 OK + AppResponse<GetPostResponse>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Assessment against linked issues

Objective Addressed Explanation
비로그인(세션 없는) 사용자도 /api/posts/{id} 또는 동등 엔드포인트로 게시글 조회 가능해야 함 (#130)
기존 로그인 체크로 인해 401 반환되는 문제 해결 (#130)
세션 체크 해제 및 공개 접근 가능하도록 API 분리/구현 (#130)

Assessment against linked issues: Out-of-scope changes

(해당 변경사항 내에서는 명확히 요구사항과 무관한 기능적 코드 변경이 발견되지 않았습니다.)

Suggested reviewers

  • yooooonshine

Poem

🐰
비밀 없는 게시글, 모두에게 공개!
로그인 없이도 볼 수 있어 참 신나네.
컨트롤러와 서비스, 테스트도 빼곡히,
토끼는 깡총깡총 코드 리뷰하러 가네!
🌱✨

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.


📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 10342e7 and 49fce97.

📒 Files selected for processing (1)
  • src/main/java/hanium/modic/backend/web/post/controller/PublicPostController.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/hanium/modic/backend/web/post/controller/PublicPostController.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch modic_backend_130

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • 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.
  • 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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for 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 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 for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (8)
src/main/java/hanium/modic/backend/domain/post/service/PostService.java (2)

121-123: 주석과 구현 불일치(null vs false) 정정 필요

주석은 “null로 설정”이라고 되어 있으나 실제 코드는 false를 설정합니다. 문서-구현 일관성 유지가 필요합니다.

-		// 비로그인 사용자이므로 좋아요 여부는 null로 설정
+		// 비로그인 사용자이므로 좋아요 여부는 false로 설정

105-126: 중복 로직 정리 제안(getPost vs getPostForPublic)

두 메서드에서 조회/매핑 로직이 상당 부분 중복됩니다. 공통 매핑을 담당하는 private 헬퍼(예: assembleResponse(postId, currentUserIdOpt))로 추출하면 가독성과 유지보수성이 향상됩니다.

src/main/java/hanium/modic/backend/web/post/controller/PublicPostController.java (1)

18-19: 생성자 접근 수준 PROTECTED 사용 검토

Spring이 리플렉션으로 주입하긴 하나, 컨벤션상 컨트롤러의 필수 생성자는 public이 일반적입니다. @RequiredArgsConstructor에서 access 옵션 제거(=public) 고려 바랍니다.

src/test/java/hanium/modic/backend/domain/post/service/PostServiceTest.java (2)

204-246: 공개 조회 서비스 단위 테스트 케이스: 전반적으로 적절합니다

  • 공개 조회에서 isLikedByUser 미호출 검증이 명확합니다.
  • likeCount, 이미지 매핑까지 검증되어 신뢰성이 좋습니다.

추가 제안:

  • 작성자 조회 실패(USER_NOT_FOUND_EXCEPTION) 케이스도 하나 추가하면 방어적 커버리지가 더 좋아집니다.

254-263: 예외 시 사이드이펙트 없는지 검증 충실 — 좋습니다

POST_NOT_FOUND 시 이미지/좋아요 카운트 호출이 일어나지 않음을 검증한 점 좋습니다. 동일 패턴으로 USER_NOT_FOUND 시에도 호출이 없음을 검증하는 케이스를 고려해 보세요.

src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java (3)

85-86: 주석 수정 필요(null 언급 불일치)

검증은 false를 기대하고 있으나 주석은 “null 값 확인”으로 되어 있습니다. 혼동 방지 차원에서 주석을 false 값 확인으로 수정하세요.

-			.andExpect(jsonPath("$.data.isLikedByCurrentUser").value(false)) // null 값 확인
+			.andExpect(jsonPath("$.data.isLikedByCurrentUser").value(false)) // false 값 확인

30-33: 테스트 단순화: BaseControllerTest 상속 불필요 가능성

@WebMvcTest + @AutoConfigureMockMvc(addFilters = false) 조합에서는 보안 필터가 비활성화되므로, BaseControllerTest 상속이 불필요할 수 있습니다. 테스트 격리를 위해 상속 제거를 고려하세요.


74-96: 입력 검증 케이스 보강 제안(@positive 도입 시)

컨트롤러에 @Validated/@positive를 적용한다면, 음수/0 ID에 대한 400 응답 테스트를 추가하면 좋습니다. 현재는 비숫자 문자열 케이스만 있습니다.

추가 예시(메서드 추가):

@Test
@DisplayName("공개 게시글 조회 - 음수 ID는 400 반환")
void getPost_NegativeId_ShouldReturnBadRequest() throws Exception {
	mockMvc.perform(get("/api/public/posts/{id}", -1))
		.andExpect(status().isBadRequest());
	verify(postService, never()).getPostForPublic(any());
}

@Test
@DisplayName("공개 게시글 조회 - 0 ID는 400 반환")
void getPost_ZeroId_ShouldReturnBadRequest() throws Exception {
	mockMvc.perform(get("/api/public/posts/{id}", 0))
		.andExpect(status().isBadRequest());
	verify(postService, never()).getPostForPublic(any());
}

Also applies to: 116-126

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b7817d8 and 10342e7.

📒 Files selected for processing (4)
  • src/main/java/hanium/modic/backend/domain/post/service/PostService.java (1 hunks)
  • src/main/java/hanium/modic/backend/web/post/controller/PublicPostController.java (1 hunks)
  • src/test/java/hanium/modic/backend/domain/post/service/PostServiceTest.java (1 hunks)
  • src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/test/java/hanium/modic/backend/domain/post/service/PostServiceTest.java (2)
src/test/java/hanium/modic/backend/domain/user/factory/UserFactory.java (1)
  • UserFactory (9-29)
src/test/java/hanium/modic/backend/domain/image/entityfactory/ImageFactory.java (1)
  • ImageFactory (16-63)
src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java (3)
src/test/java/hanium/modic/backend/base/BaseControllerTest.java (1)
  • BaseControllerTest (13-49)
src/test/java/hanium/modic/backend/domain/post/entityfactory/PostFactory.java (1)
  • PostFactory (10-36)
src/test/java/hanium/modic/backend/domain/user/factory/UserFactory.java (1)
  • UserFactory (9-29)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (1)
src/main/java/hanium/modic/backend/web/post/controller/PublicPostController.java (1)

1-32: 보안 설정 확인 완료: /api/public/posts/** 접근 허용됨

  • SecurityConfig.java 38번째 줄의 .anyRequest().permitAll() 설정으로 모든 엔드포인트가 비로그인 상태에서도 접근 가능함을 확인했습니다.

추후 보안 정책 강화 시, public API 경로만 별도 permitAll 처리하고 나머지 요청은 인증을 요구하도록 세부 권한 설정을 고려해보세요.

Comment on lines +111 to +116
final String userName = userEntity.getName();
final String userImage = userEntity.getUserImageUrl();
final boolean hasUserImage = userImage != null;
final String userEmail = userEntity.getEmail();

List<PostImageEntity> postImages = postImageEntityRepository.findAllByPostId(id);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

공개 API에서 사용자 이메일 노출은 PII 위험 — 반환에서 제거/마스킹을 권장

비로그인 공개 엔드포인트에서 userEmail을 그대로 노출하는 것은 개인정보(PII) 유출 리스크가 있습니다. 기존 로그인 전용 응답 DTO를 재사용하더라도, 공개용 서비스에서는 이메일을 제거하거나 마스킹하는 편이 안전합니다.

  • 권장안 A(간단/안전): 공개 API에서는 userEmail을 null로 반환
  • 권장안 B(대안): 마스킹 처리(예: a***@example.com). 별도 유틸 추가 필요

테스트(PublicPostControllerTest)에서 이메일을 검증하고 있으므로, 정책상 비노출이 맞다면 해당 검증을 제거/수정해야 합니다.

적용 예시(간단 비노출):

-		final String userEmail = userEntity.getEmail();
+		// 공개 API: 이메일 비노출(PII 보호)
+		final String userEmail = null;

Also applies to: 121-126

🤖 Prompt for AI Agents
In src/main/java/hanium/modic/backend/domain/post/service/PostService.java
around lines 111 to 116 and 121 to 126, the userEmail is exposed in the public
API response, which risks leaking personally identifiable information (PII). To
fix this, modify the code to either set userEmail to null before returning it in
the public API or apply masking to the email address. Additionally, update or
remove any tests in PublicPostControllerTest that validate the presence of
userEmail to align with this new policy.

Comment on lines +91 to +92
.andExpect(jsonPath("$.data.userName").value(mockUser.getName()))
.andExpect(jsonPath("$.data.userEmail").value(mockUser.getEmail()));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

PII 보호 정책을 따른다면 이메일 검증 제거 필요

공개 엔드포인트에서 이메일 비노출로 변경(권장)하는 경우, 해당 검증은 제거 또는 null 기대값으로 수정되어야 합니다.

-			.andExpect(jsonPath("$.data.userName").value(mockUser.getName()))
-			.andExpect(jsonPath("$.data.userEmail").value(mockUser.getEmail()));
+			.andExpect(jsonPath("$.data.userName").value(mockUser.getName()));
+			// 공개 API에서는 userEmail 비노출(PII 보호). 필요 시 마스킹으로 변경 가능.
+			// .andExpect(jsonPath("$.data.userEmail").doesNotExist());
📝 Committable suggestion

‼️ 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.

Suggested change
.andExpect(jsonPath("$.data.userName").value(mockUser.getName()))
.andExpect(jsonPath("$.data.userEmail").value(mockUser.getEmail()));
@@ src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java
- .andExpect(jsonPath("$.data.userName").value(mockUser.getName()))
- .andExpect(jsonPath("$.data.userEmail").value(mockUser.getEmail()));
+ .andExpect(jsonPath("$.data/userName").value(mockUser.getName()));
+ // 공개 API에서는 userEmail 비노출(PII 보호). 필요 시 마스킹으로 변경 가능.
+ // .andExpect(jsonPath("$.data.userEmail").doesNotExist());
🤖 Prompt for AI Agents
In
src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java
at lines 91-92, the test currently verifies the user's email in the JSON
response, which may expose PII against policy. To fix this, remove the email
verification assertion or change it to expect a null or absent value for the
email field to comply with PII protection guidelines for public endpoints.

- @validated 어노테이션 추가로 파라미터 검증 활성화
- @positive 어노테이션으로 ID 파라미터 양수 검증
- API 문서 설명 개선: likeCount 포함, isLikedByCurrentUser 고정값 명시
- 400 에러 응답 문서화 추가

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/api/posts/{id} GET method 정책 수정 요청

2 participants