Skip to content

πŸ“ˆ[뢄석좔가] &⚑️[μ„±λŠ₯ ν–₯상] Prometheus & Grafana λͺ¨λ‹ˆν„°λ§ ν™˜κ²½ ꡬ좕 & μ„±λŠ₯ ν–₯상 - #101

Merged
passionryu merged 12 commits into
devfrom
feat/hot-topic
Jul 18, 2025

Conversation

@wjkim9

@wjkim9 wjkim9 commented Jul 18, 2025

Copy link
Copy Markdown
Collaborator

Grafana둜 Prometheus 데이터 μ‹œκ°ν™”

image
image

SpringBoot μ„œλ²„μ™€ Redis μ„œλ²„μ— λŒ€ν•œ λͺ¨λ‹ˆν„°λ§ μ„ΈνŒ… κ΅¬ν˜„


Redis-cache μ„œλ²„λ₯Ό ν™œμš©ν•˜μ—¬ λ‘œλ“œ μ‹œκ°„ κ°œμ„ 

image

API 호좜 μ‹œ DB 접속 ν›„ λ°˜ν™˜> 608ms
API 호좜 μ‹œ μΊμ‹œμ—μ„œ λ°˜ν™˜ > 1ms

ν•­λͺ© κΈ°μ‘΄ μ‹œκ°„ μΊμ‹œ 이후 μ„±λŠ₯ ν–₯상λ₯ 
DB 쑰회 608ms 1ms 99.84%
ES 쑰회 189ms 0ms 100%

DB 쿼리 κ°œμ„  및 인덱슀 μΆ”κ°€

쀑볡 제거 둜직 μˆ˜ν–‰ μ‹œ SQL에 볡합 인덱슀λ₯Ό μ μš©λ°›μ„ 수 μžˆκ²Œλ” 쿼리λ₯Ό λ³€κ²½
처리 μ‹œκ°„ κ°œμ„ 

Summary by CodeRabbit

  • μ‹ κ·œ κΈ°λŠ₯

    • Redis 기반 캐싱 κΈ°λŠ₯이 λ„μž…λ˜μ–΄ 인기 ν† ν”½ 및 λ‰΄μŠ€ 리슀트 쑰회 μ„±λŠ₯이 ν–₯μƒλ˜μ—ˆμŠ΅λ‹ˆλ‹€.
    • Prometheus 및 Grafanaλ₯Ό ν†΅ν•œ μ„œλΉ„μŠ€ λͺ¨λ‹ˆν„°λ§μ΄ μ§€μ›λ©λ‹ˆλ‹€.
    • Redis Exporter μ„œλΉ„μŠ€κ°€ μΆ”κ°€λ˜μ–΄ Redis μƒνƒœ λͺ¨λ‹ˆν„°λ§μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€.
  • 버그 μˆ˜μ •

    • λ‰΄μŠ€ 쀑볡 μ‚­μ œ 및 "[속보]" νƒœκ·Έ λ‰΄μŠ€ μ‚­μ œ 둜직의 λ‚ μ§œ ν•„ν„°κ°€ 더 μ •ν™•ν•˜κ²Œ κ°œμ„ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
  • μ„±λŠ₯ κ°œμ„ 

    • λ°μ΄ν„°λ² μ΄μŠ€ λ‰΄μŠ€ ν…Œμ΄λΈ”μ— 볡합 μΈλ±μŠ€κ°€ μΆ”κ°€λ˜μ–΄ 검색 속도가 ν–₯μƒλ˜μ—ˆμŠ΅λ‹ˆλ‹€.
  • μ„€μ •

    • μΊμ‹œ 및 λͺ¨λ‹ˆν„°λ§ κ΄€λ ¨ ν™˜κ²½μ„€μ •μ΄ μΆ”κ°€ 및 κ°œμ„ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
  • 기타

    • μ„€μ • μ €μž₯ μ‹œ ν—ˆμš© 개수 초과 μ˜ˆμ™Έκ°€ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.
    • 일뢀 경둜의 JWT 인증 μ œμ™Έ 정책이 λ³€κ²½λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

wjkim9 added 9 commits July 17, 2025 10:03
μ½”λ“œ μƒμ˜ FIXME 리슀트 μˆ˜ν–‰ν•  것.
IntelliJ μžλ™ ꡬ성 폴더 μΆ”κ°€
Prometheusλ₯Ό 톡해 SpringBoot μ„œλ²„μ™€ Redis μ„œλ²„ 데이터 μˆ˜μ§‘ν•˜μ—¬,
Grafana둜 λŒ€μ‹œλ³΄λ“œ κ΅¬ν˜„(μ‹œκ°ν™”)
DB및 ElasticSearch μ„œλ²„μ— λŒ€ν•œ μ ‘κ·Ό 횟수λ₯Ό 쀄이고 μ„±λŠ₯을 λΉ„μ•½μ μœΌλ‘œ ν–₯μƒμ‹œν‚΄
쀑볡 제거 λ‘œμ§μ—μ„œ SQL을 INDEXλ₯Ό μ μš©λ°›μ„ 수 μžˆλ„λ‘ μˆ˜μ •
쀑볡 제거 μ‹œ 볡합 INDEXλ₯Ό μ°Έμ‘°ν•˜μ—¬ μ„±λŠ₯이 ν–₯상 됨
@coderabbitai

coderabbitai Bot commented Jul 18, 2025

Copy link
Copy Markdown

Walkthrough

이번 λ³€κ²½ 사항은 Redis 기반 μΊμ‹œ λ„μž…, Prometheus 및 Grafana λͺ¨λ‹ˆν„°λ§ 인프라 μΆ”κ°€, λ‰΄μŠ€ λ°μ΄ν„°λ² μ΄μŠ€ 인덱슀 μ΅œμ ν™”, 일뢀 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 κ°œμ„ , 그리고 μΊμ‹œ 및 λͺ¨λ‹ˆν„°λ§ κ΄€λ ¨ μ„€μ • 파일 μΆ”κ°€ 및 μˆ˜μ •μ΄ ν¬ν•¨λ©λ‹ˆλ‹€. λ˜ν•œ, JWT ν•„ν„° μ˜ˆμ™Έ κ²½λ‘œμ™€ 쀑볡 λ‰΄μŠ€ μ‚­μ œ 쿼리 둜직이 μ‘°μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Changes

파일/경둜 κ·Έλ£Ή λ³€κ²½ μš”μ•½
.gitignore .idea 디렉토리 λ¬΄μ‹œ ν•­λͺ© μΆ”κ°€
SpringBoot/build.gradle, SpringBoot/src/main/resources/application.properties Prometheus, Micrometer, Redis μΊμ‹œ κ΄€λ ¨ μ˜μ‘΄μ„± 및 μ„€μ • μΆ”κ°€, λͺ¨λ‹ˆν„°λ§ μ—”λ“œν¬μΈνŠΈ 및 νƒœκ·Έ μ„€μ •
SpringBoot/database/init.sql λ‰΄μŠ€ ν…Œμ΄λΈ”μ— 볡합 인덱슀 2μ’… μΆ”κ°€ 및 주석 보강
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/HotTopic_Description "## κΈ°λŠ₯ μ„€λͺ…" 헀더 뒀에 빈 쀄 μΆ”κ°€ (ν¬λ§·νŒ… λ³€κ²½)
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/service/HotTopicService.java Redis μΊμ‹œ 적용, λͺ…μ‹œμ  μƒμ„±μž μΆ”κ°€, μΊμ‹œ ν‚€/만료 둜직 및 λ‘œκΉ… μΆ”κ°€
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/Controller/SettingController.java 컨트둀러 λ©”μ„œλ“œ λ°˜ν™˜ νƒ€μž…μ„ ResponseEntity둜 λͺ…μ‹œν™”ν•˜κ³ , μ‚­μ œ λ©”μ„œλ“œμ˜ μ˜ˆμ™Έ 처리 제거 및 κ°„μ†Œν™”
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/service/SettingService.java μ‚¬μš©μž 쑰회 및 μ„€μ • 개수 초과 μ‹œ μ˜ˆμ™Έ 처리 μΆ”κ°€, μ €μž₯/μˆ˜μ •/μ‚­μ œ λ©”μ„œλ“œ κ°„μ†Œν™”, μ„€μ • 개수 μ œν•œ 검사 λ©”μ„œλ“œ μΆ”κ°€
SpringBoot/src/main/java/Baemin/News_Deliver/Global/Config/RedisConfig.java μΊμ‹œμš© RedisConnectionFactory, RedisTemplate, ObjectMapper 빈 μΆ”κ°€ 및 κΈ°μ‘΄ μ„Έμ…˜ Redis와 뢄리
SpringBoot/src/main/java/Baemin/News_Deliver/Global/Exception/ErrorCode.java SETTING_LIMIT_EXCEEDED μ—λŸ¬ μ½”λ“œ μΆ”κ°€
SpringBoot/src/main/java/Baemin/News_Deliver/Global/JWT/JwtAuthenticationFilter.java JWT ν•„ν„° μ˜ˆμ™Έ κ²½λ‘œμ—μ„œ /api/auth/, / 제거, 정적 λ¦¬μ†ŒμŠ€ 및 OAuth κ΄€λ ¨ 경둜만 μ˜ˆμ™Έ 처리
SpringBoot/src/main/java/Baemin/News_Deliver/Global/News/Batch/listener/BatchJobCompletionListener.java λ‰΄μŠ€ 쀑볡 μ‚­μ œ 쿼리의 λ‚ μ§œ 쑰건 λ³€κ²½ 및 "[속보]" 포함 λ‰΄μŠ€λ„ μ‚­μ œν•˜λ„λ‘ ν™•μž₯
SpringBoot/src/main/java/Baemin/News_Deliver/Global/News/ElasticSearch/service/NewsEsService.java λ‰΄μŠ€ 적재 쿼리의 λ‚ μ§œ ν•„ν„°λ₯Ό λ²”μœ„ 쑰건으둜 λ³€κ²½
SpringBoot/src/main/java/Baemin/News_Deliver/NewsDeliverApplication.java @EnableCaching μ• λ…Έν…Œμ΄μ…˜ μΆ”κ°€
docker-compose.yml, monitoring/prometheus.yml Prometheus, Grafana, Redis Exporter 3μ’… μ„œλΉ„μŠ€ μΆ”κ°€ 및 λ³Όλ₯¨/λ„€νŠΈμ›Œν¬ μ„€μ •, Prometheus 슀크랩 νƒ€κ²Ÿ ꡬ성
SpringBoot/src/main/java/Baemin/News_Deliver/Global/Exception/GlobalExceptionHandler.java @RestControllerAdvice μ• λ…Έν…Œμ΄μ…˜ μΆ”κ°€ 및 SettingException ν•Έλ“€λŸ¬ μ½”λ“œ μŠ€νƒ€μΌ μˆ˜μ •

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant HotTopicService
    participant RedisCache
    participant DB
    participant ES

    Client->>HotTopicService: getHotTopicList()
    HotTopicService->>RedisCache: μΊμ‹œ 쑰회(hottopic:daily)
    alt μΊμ‹œ HIT
        RedisCache-->>HotTopicService: μΊμ‹œλœ 리슀트 λ°˜ν™˜
        HotTopicService-->>Client: 리슀트 λ°˜ν™˜
    else μΊμ‹œ MISS
        HotTopicService->>DB: μ–΄μ œμ˜ HotTopic 10개 쑰회
        HotTopicService->>RedisCache: μΊμ‹œ μ €μž₯(만료: 내일 0μ‹œ)
        HotTopicService-->>Client: 리슀트 λ°˜ν™˜
    end

    Client->>HotTopicService: getNewsList(keyword, size)
    HotTopicService->>RedisCache: μΊμ‹œ 쑰회(hottopic:news:{keyword})
    alt μΊμ‹œ HIT
        RedisCache-->>HotTopicService: μΊμ‹œλœ λ‰΄μŠ€ 리슀트 λ°˜ν™˜
        HotTopicService-->>Client: 리슀트 λ°˜ν™˜
    else μΊμ‹œ MISS
        HotTopicService->>ES: ν‚€μ›Œλ“œ λ‰΄μŠ€ 검색
        HotTopicService->>RedisCache: μΊμ‹œ μ €μž₯(만료: 내일 0μ‹œ)
        HotTopicService-->>Client: 리슀트 λ°˜ν™˜
    end
Loading
sequenceDiagram
    participant BatchJob
    participant DB

    BatchJob->>DB: 쀑볡 λ‰΄μŠ€ 및 "[속보]" 포함 λ‰΄μŠ€ μ‚­μ œ 쿼리 μ‹€ν–‰
    Note right of DB: published_at λ²”μœ„ 및 title 쑰건 λ™μ‹œ 적용
Loading
sequenceDiagram
    participant User
    participant SettingController
    participant SettingService
    participant UserRepository

    User->>SettingController: saveSetting(settingDTO)
    SettingController->>SettingService: saveSetting(settingDTO)
    SettingService->>UserRepository: findById(userId)
    alt User μ—†μŒ
        SettingService-->>SettingController: SettingException(USER_NOT_FOUND)
    else User 있음
        SettingService->>SettingService: isSettingLimitExceeded(user)
        alt μ œν•œ 초과
            SettingService-->>SettingController: SettingException(SETTING_LIMIT_EXCEEDED)
        else μ œν•œ 미초과
            SettingService->>SettingService: Setting μ—”ν‹°ν‹° 생성 및 μ‚¬μš©μž μ—°κ²°
            SettingService-->>SettingController: μ™„λ£Œ
        end
    end
Loading
✨ Finishing Touches
  • πŸ“ Generate Docstrings

πŸͺ§ 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.
    • @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 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 docstrings to generate docstrings for this 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 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (6)
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/Controller/SettingController.java (1)

75-75: TODO ν•­λͺ©μ— λŒ€ν•œ 도움 μ œμ•ˆ

μ„€μ • 개수 μ œν•œ(3개) 검증 둜직이 아직 κ΅¬ν˜„λ˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. μ„œλΉ„μŠ€ λ ˆμ΄μ–΄μ—μ„œ κ΄€λ ¨ 검증 λ©”μ„œλ“œκ°€ μ€€λΉ„λ˜μ–΄ μžˆλŠ” κ²ƒμœΌλ‘œ λ³΄μž…λ‹ˆλ‹€.

이 검증 λ‘œμ§μ„ κ΅¬ν˜„ν•˜κ±°λ‚˜ μƒˆλ‘œμš΄ 이슈λ₯Ό μƒμ„±ν•˜μ—¬ μΆ”μ ν•˜λŠ” 것을 λ„μ™€λ“œλ¦΄κΉŒμš”?

SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/service/SettingService.java (1)

246-253: μ„€μ • μ œν•œ 검증 둜직 κ΅¬ν˜„ ν•„μš”

μ„€μ • 개수 μ œν•œ 검증을 μœ„ν•œ λ©”μ„œλ“œκ°€ μŠ€ν…μœΌλ‘œλ§Œ κ΅¬ν˜„λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. μ‹€μ œ 검증 둜직이 ν•„μš”ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같은 κ΅¬ν˜„μ„ μ œμ•ˆλ“œλ¦½λ‹ˆλ‹€:

private boolean isSettingLimitExceeded(User user) {
    long activeSettingsCount = settingRepository.countActiveSettingsByUser(user, LocalDateTime.now());
    return activeSettingsCount >= 3;
}

이 κ΅¬ν˜„μ„ μœ„ν•΄μ„œλŠ” SettingRepository에 countActiveSettingsByUser λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€. κ΅¬ν˜„μ„ λ„μ™€λ“œλ¦΄κΉŒμš”?

SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/HotTopic_Description (1)

7-7: μœ μš©ν•œ μ•Œλ¦Ό μ½”λ©˜νŠΈμž…λ‹ˆλ‹€.

FIXME μ½”λ©˜νŠΈλ₯Ό 톡해 ν–₯ν›„ κ°œλ°œμ—μ„œ μ²˜λ¦¬ν•΄μ•Ό ν•  μš”κ΅¬μ‚¬ν•­μ„ λͺ…ν™•νžˆ λ¬Έμ„œν™”ν–ˆμŠ΅λ‹ˆλ‹€.

이 μž‘μ—…μ„ μΆ”μ ν•˜κΈ° μœ„ν•œ 이슈λ₯Ό μƒμ„±ν•˜λŠ” 것을 κ³ λ €ν•΄λ³΄μ‹œκ² μŠ΅λ‹ˆκΉŒ? 도움이 ν•„μš”ν•˜μ‹œλ©΄ 말씀해 μ£Όμ„Έμš”.

monitoring/prometheus.yml (1)

25-25: 파일 끝에 κ°œν–‰ 문자λ₯Ό μΆ”κ°€ν•˜μ„Έμš”.

YAML 파일 ν‘œμ€€μ— 따라 파일 끝에 κ°œν–‰ λ¬Έμžκ°€ ν•„μš”ν•©λ‹ˆλ‹€.

-      - targets: [ 'redis-session2-exporter:9121' ]
+      - targets: [ 'redis-session2-exporter:9121' ]
+
docker-compose.yml (1)

167-197: Redis μ΅μŠ€ν¬ν„° ꡬ성이 μš°μˆ˜ν•©λ‹ˆλ‹€.

λͺ¨λ“  Redis μΈμŠ€ν„΄μŠ€μ— λŒ€ν•œ λͺ¨λ‹ˆν„°λ§ μ„€μ •κ³Ό 포트 좩돌 λ°©μ§€κ°€ 잘 κ΅¬μ„±λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

선택적 κ°œμ„ μ‚¬ν•­: redis-session1-exporter와 redis-session2-exporter에도 ν•΄λ‹Ή Redis μ„œλΉ„μŠ€μ— λŒ€ν•œ μ˜μ‘΄μ„±μ„ μΆ”κ°€ν•˜λŠ” 것을 κ³ λ €ν•΄λ³΄μ„Έμš”:

  redis-session1-exporter:
    image: oliver006/redis_exporter
    container_name: redis-session1-exporter
    command:
      - '--redis.addr=redis://redis-session1:6379'
    ports:
      - "9122:9121"
+   depends_on:
+     - redis-session1
    networks:
      - backend
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/service/HotTopicService.java (1)

155-176: λ‰΄μŠ€ 리슀트 캐싱 κ΅¬ν˜„μ΄ 일관성 있게 잘 κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

ν‚€μ›Œλ“œ 기반 μΊμ‹œ ν‚€ μ „λž΅κ³Ό μ„±λŠ₯ λ‘œκΉ…μ΄ ν•«ν† ν”½ 캐싱과 μΌκ΄€λ˜κ²Œ μ μš©λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

선택적 κ°œμ„ μ‚¬ν•­: ν‚€μ›Œλ“œ 기반 λ‰΄μŠ€ 검색 결과의 μΊμ‹œ 만료 μ „λž΅μ„ ν•«ν† ν”½κ³Ό λ‹€λ₯΄κ²Œ μ„€μ •ν•˜λŠ” 것을 κ³ λ €ν•΄λ³΄μ„Έμš”. 예λ₯Ό λ“€μ–΄, λ‰΄μŠ€ 검색 κ²°κ³ΌλŠ” 더 짧은 TTL을 κ°€μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€:

- long ttlSeconds = Duration.between(
-         LocalDateTime.now(),
-         LocalDate.now().plusDays(1).atStartOfDay()
- ).getSeconds();
+ // λ‰΄μŠ€ 검색 κ²°κ³ΌλŠ” 1μ‹œκ°„ μΊμ‹œ
+ long ttlSeconds = Duration.ofHours(1).getSeconds();
πŸ“œ Review details

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between a25a67a and 06773e3.

πŸ“’ Files selected for processing (16)
  • .gitignore (1 hunks)
  • SpringBoot/build.gradle (1 hunks)
  • SpringBoot/database/init.sql (1 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/HotTopic_Description (1 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/service/HotTopicService.java (4 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/Controller/SettingController.java (1 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/service/SettingService.java (2 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Global/Config/RedisConfig.java (2 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Global/Exception/ErrorCode.java (1 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Global/JWT/JwtAuthenticationFilter.java (1 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Global/News/Batch/listener/BatchJobCompletionListener.java (1 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Global/News/ElasticSearch/service/NewsEsService.java (1 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/NewsDeliverApplication.java (1 hunks)
  • SpringBoot/src/main/resources/application.properties (2 hunks)
  • docker-compose.yml (1 hunks)
  • monitoring/prometheus.yml (1 hunks)
🧰 Additional context used
πŸͺ› YAMLlint (1.37.1)
monitoring/prometheus.yml

[error] 25-25: no new line character at the end of file

(new-line-at-end-of-file)

πŸ”‡ Additional comments (22)
SpringBoot/src/main/java/Baemin/News_Deliver/Global/Exception/ErrorCode.java (1)

51-51: μƒˆλ‘œμš΄ μ—λŸ¬ μ½”λ“œ μΆ”κ°€ 승인

μ„€μ • 개수 μ œν•œ μ΄ˆκ³Όμ— λŒ€ν•œ μƒˆλ‘œμš΄ μ—λŸ¬ μ½”λ“œκ°€ 적절히 μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€. λͺ…λͺ… κ·œμΉ™μ„ 잘 λ”°λ₯΄κ³  있으며, HTTP μƒνƒœ μ½”λ“œλ„ μ μ ˆν•©λ‹ˆλ‹€.

.gitignore (1)

2-2: 쒋은 λ³€κ²½μ‚¬ν•­μž…λ‹ˆλ‹€.

IntelliJ IDEA ν”„λ‘œμ νŠΈ νŒŒμΌμ„ .gitignore에 μΆ”κ°€ν•˜λŠ” 것은 ν‘œμ€€μ μΈ κ΄€λ‘€μž…λ‹ˆλ‹€. 이λ₯Ό 톡해 IDE μ„€μ • 파일이 μ €μž₯μ†Œμ— μ»€λ°‹λ˜λŠ” 것을 λ°©μ§€ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

SpringBoot/src/main/java/Baemin/News_Deliver/NewsDeliverApplication.java (2)

5-5: μ μ ˆν•œ import μΆ”κ°€μž…λ‹ˆλ‹€.

Spring의 캐싱 κΈ°λŠ₯을 ν™œμ„±ν™”ν•˜κΈ° μœ„ν•œ μ˜¬λ°”λ₯Έ importμž…λ‹ˆλ‹€.


12-12: 캐싱 κΈ°λŠ₯ ν™œμ„±ν™”κ°€ μ˜¬λ°”λ₯΄κ²Œ κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

@EnableCaching μ–΄λ…Έν…Œμ΄μ…˜μ„ 톡해 Spring의 캐싱 좔상화λ₯Ό ν™œμ„±ν™”ν–ˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” Redis μΊμ‹œ κ΅¬ν˜„κ³Ό μΌμΉ˜ν•˜λ©° μ˜¬λ°”λ₯Έ μœ„μΉ˜μ— λ°°μΉ˜λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

SpringBoot/src/main/resources/application.properties (3)

15-15: Redis μΊμ‹œ νƒ€μž… 섀정이 μ˜¬λ°”λ₯΄κ²Œ κ΅¬μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Spring Boot의 μΊμ‹œ 좔상화λ₯Ό μœ„ν•œ μ μ ˆν•œ Redis μ„€μ •μž…λ‹ˆλ‹€.


18-18: Redis νƒ€μž„μ•„μ›ƒ μ„€μ • κ²€ν† κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

24μ‹œκ°„μ˜ Redis νƒ€μž„μ•„μ›ƒμ€ 맀우 κΈ΄ μ‹œκ°„μž…λ‹ˆλ‹€. 이 섀정이 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μš”κ΅¬μ‚¬ν•­κ³Ό μΌμΉ˜ν•˜λŠ”μ§€ ν™•μΈν•΄μ£Όμ„Έμš”.

λ‹€μŒ 사항듀을 κ²€ν† ν•΄λ³΄μ„Έμš”:

  • μΊμ‹œ λ°μ΄ν„°μ˜ νŠΉμ„±κ³Ό 유효 κΈ°κ°„
  • λ©”λͺ¨λ¦¬ μ‚¬μš©λŸ‰μ— λŒ€ν•œ 영ν–₯
  • 데이터 일관성 μš”κ΅¬μ‚¬ν•­

89-90: Prometheus λͺ¨λ‹ˆν„°λ§ 섀정이 μ μ ˆν•˜κ²Œ κ΅¬μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

health, info, prometheus μ—”λ“œν¬μΈνŠΈλ₯Ό λ…ΈμΆœν•˜κ³  μ• ν”Œλ¦¬μΌ€μ΄μ…˜λ³„ λ©”νŠΈλ¦­ νƒœκ·Έλ₯Ό μΆ”κ°€ν•œ 것은 쒋은 λͺ¨λ‹ˆν„°λ§ μ„€μ •μž…λ‹ˆλ‹€.

SpringBoot/build.gradle (1)

85-91: λͺ¨λ‹ˆν„°λ§ 및 캐싱 μ˜μ‘΄μ„± μΆ”κ°€κ°€ μ μ ˆν•©λ‹ˆλ‹€.

Prometheus λͺ¨λ‹ˆν„°λ§κ³Ό Redis 캐싱 κΈ°λŠ₯을 μœ„ν•œ μ˜μ‘΄μ„±μ΄ μ˜¬λ°”λ₯΄κ²Œ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€. Spring Boot의 μ˜μ‘΄μ„± 관리λ₯Ό ν™œμš©ν•˜μ—¬ 버전 좩돌 없이 톡합할 수 μžˆμŠ΅λ‹ˆλ‹€.

monitoring/prometheus.yml (1)

1-25: Prometheus 섀정이 λͺ¨λ‹ˆν„°λ§ λͺ©μ μ— μ ν•©ν•©λ‹ˆλ‹€.

Spring Boot μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό μ—¬λŸ¬ Redis μΈμŠ€ν„΄μŠ€μ— λŒ€ν•œ λͺ¨λ‹ˆν„°λ§ 섀정이 μ˜¬λ°”λ₯΄κ²Œ κ΅¬μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 5초 μŠ€ν¬λž˜ν•‘ 간격은 개발 ν™˜κ²½μ— μ μ ˆν•©λ‹ˆλ‹€.

SpringBoot/src/main/java/Baemin/News_Deliver/Global/News/ElasticSearch/service/NewsEsService.java (1)

97-101: SQL 쿼리 μ΅œμ ν™”κ°€ μ„±λŠ₯ ν–₯상에 도움이 λ©λ‹ˆλ‹€.

λ‚ μ§œ 필터링 λ‘œμ§μ„ DATE() ν•¨μˆ˜ μ‚¬μš©μ—μ„œ νƒ€μž„μŠ€νƒ¬ν”„ λ²”μœ„ 쑰건으둜 λ³€κ²½ν•œ 것은 쒋은 κ°œμ„ μž…λ‹ˆλ‹€. 이 λ³€κ²½μœΌλ‘œ 인해 idx_news_published_sections 볡합 인덱슀λ₯Ό 효율적으둜 ν™œμš©ν•  수 μžˆμ–΄ 쿼리 μ„±λŠ₯이 ν–₯μƒλ©λ‹ˆλ‹€.

SpringBoot/database/init.sql (1)

114-118: λ°μ΄ν„°λ² μ΄μŠ€ 인덱슀 μ΅œμ ν™”κ°€ 잘 μ„€κ³„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

μΆ”κ°€λœ 볡합 μΈλ±μŠ€λ“€μ΄ 쿼리 μ„±λŠ₯ ν–₯상에 νš¨κ³Όμ μž…λ‹ˆλ‹€:

  • idx_news_published_sections: λ‚ μ§œλ³„ μ„Ήμ…˜ 쑰회 μ„±λŠ₯ ν–₯상
  • idx_news_dup: 쀑볡 μ‚­μ œ 둜직의 ROW_NUMBER() μ—°μ‚° μ΅œμ ν™”

각 인덱슀의 컬럼 μˆœμ„œλ„ 쿼리 νŒ¨ν„΄μ— 맞게 적절히 μ„€μ •λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

SpringBoot/src/main/java/Baemin/News_Deliver/Global/News/Batch/listener/BatchJobCompletionListener.java (1)

41-53: 쀑볡 μ‚­μ œ 둜직 κ°œμ„ μ΄ μ’‹μ§€λ§Œ 속보 μ‚­μ œ λ²”μœ„λ₯Ό ν™•μΈν•˜μ„Έμš”.

νƒ€μž„μŠ€νƒ¬ν”„ λ²”μœ„ ν•„ν„°λ§μœΌλ‘œ λ³€κ²½ν•œ 것은 인덱슀 ν™œμš© μΈ‘λ©΄μ—μ„œ μš°μˆ˜ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ [속보] μ‚­μ œ 쑰건이 λ‚ μ§œ 필터링과 OR둜 μ—°κ²°λ˜μ–΄ μžˆμ–΄ λͺ¨λ“  λ‚ μ§œμ˜ 속보가 μ‚­μ œλ  수 μžˆμŠ΅λ‹ˆλ‹€.

μ˜λ„ν•œ λ™μž‘μ΄ λ§žλŠ”μ§€ ν™•μΈν•΄μ£Όμ„Έμš”. λ§Œμ•½ μ–΄μ œ λ‚ μ§œμ˜ μ†λ³΄λ§Œ μ‚­μ œν•˜λ €λ©΄ λ‹€μŒκ³Ό 같이 μˆ˜μ •μ„ κ³ λ €ν•΄λ³΄μ„Έμš”:

-                WHERE (
-                    id IN (
-                        SELECT id FROM (
-                            SELECT id,
-                                   ROW_NUMBER() OVER (PARTITION BY title, publisher ORDER BY id) AS rn
-                            FROM news
-                            WHERE published_at >= CURDATE() - INTERVAL 1 DAY
-                              AND published_at < CURDATE()
-                        ) t
-                        WHERE t.rn > 1
-                    )
-                    OR title LIKE '%[속보]%'
-                );
+                WHERE id IN (
+                    SELECT id FROM (
+                        SELECT id,
+                               ROW_NUMBER() OVER (PARTITION BY title, publisher ORDER BY id) AS rn
+                        FROM news
+                        WHERE published_at >= CURDATE() - INTERVAL 1 DAY
+                          AND published_at < CURDATE()
+                          AND (title LIKE '%[속보]%' OR 1=1)
+                    ) t
+                    WHERE t.rn > 1 OR title LIKE '%[속보]%'
+                );
SpringBoot/src/main/java/Baemin/News_Deliver/Global/Config/RedisConfig.java (4)

3-16: ν•„μš”ν•œ μ˜μ‘΄μ„± μž„ν¬νŠΈκ°€ μ˜¬λ°”λ₯΄κ²Œ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Jackson 직렬화 및 Redis JSON μ‹œλ¦¬μ–ΌλΌμ΄μ € κ΄€λ ¨ μž„ν¬νŠΈκ°€ μΊμ‹œ κΈ°λŠ₯ κ΅¬ν˜„μ— μ μ ˆν•˜κ²Œ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.


69-75: μΊμ‹œ μ „μš© Redis μ—°κ²° νŒ©ν† λ¦¬κ°€ μ˜¬λ°”λ₯΄κ²Œ κ΅¬μ„±λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

μ„Έμ…˜μš© Redis와 λΆ„λ¦¬λœ μΊμ‹œ μ „μš© μ—°κ²° νŒ©ν† λ¦¬λ‘œ 관심사 뢄리가 잘 λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.


77-83: ObjectMapper ꡬ성이 μš°μˆ˜ν•©λ‹ˆλ‹€.

Java 8 λ‚ μ§œ/μ‹œκ°„ νƒ€μž… 지원을 μœ„ν•œ JavaTimeModule 등둝과 νƒ€μž„μŠ€νƒ¬ν”„ λΉ„ν™œμ„±ν™”κ°€ μ˜¬λ°”λ₯΄κ²Œ μ„€μ •λ˜μ–΄ μžˆμ–΄ μΊμ‹œμ—μ„œ λ‚ μ§œ 객체의 가독성이 ν–₯μƒλ©λ‹ˆλ‹€.


85-103: μΊμ‹œ μ „μš© RedisTemplate ꡬ성이 μš°μˆ˜ν•©λ‹ˆλ‹€.

JSON 직렬화λ₯Ό ν†΅ν•œ λ³΅μž‘ν•œ 객체 캐싱 지원과 λͺ…ν™•ν•œ Bean 이름 지정이 잘 λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. GenericJackson2JsonRedisSerializerλŠ” νƒ€μž… 정보λ₯Ό ν¬ν•¨ν•˜μ—¬ μ•ˆμ „ν•œ 역직렬화가 κ°€λŠ₯ν•˜μ§€λ§Œ, μ €μž₯ 곡간을 더 μ‚¬μš©ν•œλ‹€λŠ” 점을 μ°Έκ³ ν•˜μ„Έμš”.

docker-compose.yml (3)

134-143: Prometheus μ„œλΉ„μŠ€ ꡬ성이 μ˜¬λ°”λ¦…λ‹ˆλ‹€.

μ„€μ • 파일 λ§ˆμš΄νŠΈμ™€ 영ꡬ λ³Όλ₯¨ ꡬ성이 μ μ ˆν•˜κ²Œ λ˜μ–΄ μžˆμ–΄ λ©”νŠΈλ¦­ 데이터 지속성이 보μž₯λ©λ‹ˆλ‹€.


145-154: Grafana μ„œλΉ„μŠ€ ꡬ성이 μ μ ˆν•©λ‹ˆλ‹€.

μ›Ή μΈν„°νŽ˜μ΄μŠ€ 포트 λ…ΈμΆœκ³Ό λŒ€μ‹œλ³΄λ“œ 데이터 지속성을 μœ„ν•œ λ³Όλ₯¨ ꡬ성이 μ˜¬λ°”λ¦…λ‹ˆλ‹€.


204-205: λͺ¨λ‹ˆν„°λ§ λ„κ΅¬μš© 영ꡬ λ³Όλ₯¨μ΄ μ˜¬λ°”λ₯΄κ²Œ μΆ”κ°€λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

Prometheus와 Grafana의 데이터 지속성을 μœ„ν•œ λ³Όλ₯¨ ꡬ성이 μ μ ˆν•©λ‹ˆλ‹€.

SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/service/HotTopicService.java (3)

51-59: μƒμ„±μž μ£Όμž… 방식이 μ˜¬λ°”λ₯΄κ²Œ κ΅¬ν˜„λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

νŠΉμ • Redis ν…œν”Œλ¦Ώ 빈 μ£Όμž…μ„ μœ„ν•œ @qualifier μ‚¬μš©μœΌλ‘œ λͺ…μ‹œμ μΈ μƒμ„±μž μ£Όμž…μ΄ μ μ ˆν•˜κ²Œ μ μš©λ˜μ—ˆμŠ΅λ‹ˆλ‹€.


72-105: ν•«ν† ν”½ 캐싱 κ΅¬ν˜„μ΄ μš°μˆ˜ν•©λ‹ˆλ‹€.

일일 데이터 νŠΉμ„±μ— λ§žλŠ” μΊμ‹œ ν‚€ μ „λž΅, μžμ •κΉŒμ§€μ˜ TTL 계산, 그리고 μ„±λŠ₯ λ‘œκΉ…μ΄ 잘 κ΅¬ν˜„λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 특히 λ‹€μŒλ‚  μžμ •κΉŒμ§€μ˜ TTL 계산 둜직이 일일 ν•«ν† ν”½μ˜ νŠΉμ„±μ— 맀우 μ ν•©ν•©λ‹ˆλ‹€.


61-61: μΊμ‹œ ν‚€ μ „λž΅μ΄ 잘 μ •μ˜λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

μƒμˆ˜λ‘œ μ •μ˜λœ μΊμ‹œ ν‚€ 접두사λ₯Ό 톡해 λ‹€μ–‘ν•œ μΊμ‹œ 데이터 νƒ€μž…μ˜ 체계적인 관리가 κ°€λŠ₯ν•©λ‹ˆλ‹€.

Comment on lines 64 to 78
User user = userRepository.findById(settingDTO.getUserId())
.orElseThrow(() -> new SettingException(ErrorCode.USER_NOT_FOUND));

if (isSettingLimitExceeded(user)) {
throw new SettingException(ErrorCode.SETTING_LIMIT_EXCEEDED);
}

Setting setting = new Setting();
setting.setDeliveryTime(settingDTO.getDeliveryTime());
setting.setStartDate(settingDTO.getStartDate());
setting.setEndDate(settingDTO.getEndDate());
setting.setIsDeleted(false);

User user = userRepository.findById(settingDTO.getUserId())
.orElseThrow(() -> new SettingException(ErrorCode.USER_NOT_FOUND));
setting.setUser(user);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

Setting μ—”ν‹°ν‹° μ €μž₯ λˆ„λ½ 문제

User 쑰회 및 검증 λ‘œμ§μ€ 잘 κ΅¬ν˜„λ˜μ—ˆμ§€λ§Œ, Setting μ—”ν‹°ν‹°μ˜ λͺ…μ‹œμ  μ €μž₯이 λˆ„λ½λ˜μ—ˆμŠ΅λ‹ˆλ‹€. setting.getId()λ₯Ό λ°˜ν™˜ν•˜λ €λ©΄ λ¨Όμ € μ—”ν‹°ν‹°κ°€ μ €μž₯λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•˜μ—¬ Setting μ—”ν‹°ν‹°λ₯Ό μ €μž₯ν•˜μ„Έμš”:

 setting.setUser(user);
+
+settingRepository.save(setting);

 saveSettingKeyword(settingDTO, setting);
πŸ€– Prompt for AI Agents
In
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/service/SettingService.java
around lines 64 to 78, the Setting entity is created and populated but not saved
to the database, so calling setting.getId() will not work correctly. Fix this by
explicitly saving the Setting entity using the appropriate repository's save
method after setting its fields and before returning its ID.

Comment on lines 142 to 146
return path.startsWith("/login/oauth2/")
|| path.startsWith("/oauth2/")
|| path.equals("/")
|| path.startsWith("/css/")
|| path.startsWith("/js/")
|| path.startsWith("/images/");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ’‘ Verification agent

🧩 Analysis chain

JWT ν•„ν„° μ œμ™Έ 경둜 변경을 검증해야 ν•©λ‹ˆλ‹€.

/api/auth/ 및 / 경둜λ₯Ό μ œμ™Έ λͺ©λ‘μ—μ„œ μ œκ±°ν–ˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” μ€‘μš”ν•œ λ³΄μ•ˆ λ³€κ²½μ‚¬ν•­μœΌλ‘œ, ν•΄λ‹Ή κ²½λ‘œλ“€μ΄ 이제 JWT 인증을 μš”κ΅¬ν•˜κ²Œ λ©λ‹ˆλ‹€.

  • /api/auth/ κ²½λ‘œκ°€ 둜그인/νšŒμ›κ°€μž… μ—”λ“œν¬μΈνŠΈλ₯Ό ν¬ν•¨ν•˜λŠ” 경우, 이 λ³€κ²½μœΌλ‘œ 인해 접근이 λΆˆκ°€λŠ₯ν•΄μ§ˆ 수 μžˆμŠ΅λ‹ˆλ‹€
  • / 경둜 μ œμ™Έ 제거둜 메인 νŽ˜μ΄μ§€ 접근에 영ν–₯을 쀄 수 μžˆμŠ΅λ‹ˆλ‹€

λ‹€μŒ 슀크립트λ₯Ό μ‹€ν–‰ν•˜μ—¬ 영ν–₯을 λ°›λŠ” μ—”λ“œν¬μΈνŠΈλ“€μ„ ν™•μΈν•΄μ£Όμ„Έμš”:


🏁 Script executed:

#!/bin/bash
# /api/auth/ 경둜λ₯Ό μ‚¬μš©ν•˜λŠ” 컨트둀러 확인
ast-grep --pattern $'@RequestMapping($$$)
class $CLASS {
  $$$
}' | rg -A 10 -B 5 "api/auth"

# 루트 경둜 λ§€ν•‘ 확인
ast-grep --pattern $'@RequestMapping($$$)
$$$' | rg -A 5 -B 5 '^\s*"/"'

Length of output: 164


λ‹€μŒ 슀크립트둜 /api/auth 및 루트 경둜 맀핑이 μ‹€μ œλ‘œ μ‘΄μž¬ν•˜λŠ”μ§€ λ‹€μ‹œ ν™•μΈν•΄μ£Όμ„Έμš”:


🏁 Script executed:

#!/bin/bash
# 1. /api/auth 경둜 μ‚¬μš© μ—¬λΆ€ 확인
grep -R "/api/auth" -n SpringBoot/src/main/java

# 2. λ©”μ„œλ“œ/클래슀 λ ˆλ²¨μ—μ„œ 루트("/") λ§€ν•‘ 확인 (@GetMapping, @PostMapping, @RequestMapping)
grep -R -E '@(GetMapping|PostMapping|RequestMapping).*"\/"' -n SpringBoot/src/main/java

# 3. path 속성 λ°©μ‹μ˜ 루트 λ§€ν•‘ 확인 (@RequestMapping(path = "/"))
grep -R 'path *= *"/"' -n SpringBoot/src/main/java

Length of output: 1015


/api/auth 경둜 μ˜ˆμ™Έ 처리 λˆ„λ½ 확인 및 μˆ˜μ • ν•„μš”

JwtAuthenticationFilter.java의 shouldNotFilter λ©”μ„œλ“œμ— 인증 κ΄€λ ¨ μ—”λ“œν¬μΈνŠΈμΈ /api/auth/*κ°€ μ œμ™Έλ˜μ§€ μ•Šμ•„, λ‘œκ·ΈμΈΒ·ν† ν°λ°œκΈ‰Β·λ‘œκ·Έμ•„μ›ƒ API 접근이 μ°¨λ‹¨λ©λ‹ˆλ‹€. 루트(/) λ§€ν•‘ μ»¨νŠΈλ‘€λŸ¬λŠ” λ°œκ²¬λ˜μ§€ μ•Šμ•„ 별도 영ν–₯은 μ—†μœΌλ‚˜, 정적 λ¦¬μ†ŒμŠ€λ‚˜ SPA μ§„μž…μ μ΄ μžˆλŠ” 경우 μ˜ˆμ™Έ κ²€ν† κ°€ ν•„μš”ν•©λ‹ˆλ‹€.

  • μœ„μΉ˜:
    SpringBoot/src/main/java/Baemin/News_Deliver/Global/JWT/JwtAuthenticationFilter.java (μ•½ 142ν–‰)
  • μˆ˜μ • μ œμ•ˆ: /api/auth/ 경둜λ₯Ό μ œμ™Έ λͺ©λ‘μ— μΆ”κ°€ (path.startsWith("/api/auth/"))

μ˜ˆμ‹œ diff:

 return path.startsWith("/login/oauth2/")
         || path.startsWith("/oauth2/")
+        || path.startsWith("/api/auth/")
         || path.startsWith("/css/")
         || path.startsWith("/js/")
         || path.startsWith("/images/");

ν•„μš” μ‹œ 루트 경둜 μ˜ˆμ™Έκ°€ ν•„μš”ν•˜λ‹€λ©΄ || path.equals("/")도 ν•¨κ»˜ μΆ”κ°€ν•˜μ„Έμš”.

πŸ“ 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
return path.startsWith("/login/oauth2/")
|| path.startsWith("/oauth2/")
|| path.equals("/")
|| path.startsWith("/css/")
|| path.startsWith("/js/")
|| path.startsWith("/images/");
return path.startsWith("/login/oauth2/")
|| path.startsWith("/oauth2/")
|| path.startsWith("/api/auth/")
|| path.startsWith("/css/")
|| path.startsWith("/js/")
|| path.startsWith("/images/");
πŸ€– Prompt for AI Agents
In
SpringBoot/src/main/java/Baemin/News_Deliver/Global/JWT/JwtAuthenticationFilter.java
around lines 142 to 146, the shouldNotFilter method is missing exclusion for the
/api/auth/ path, causing authentication-related endpoints to be blocked. Add a
condition to exclude paths starting with "/api/auth/" by including
`path.startsWith("/api/auth/")` in the return statement. Optionally, if root
path exclusion is needed, also add `path.equals("/")`.

wjkim9 added 2 commits July 18, 2025 11:59
κΈ°μ‘΄ try ~ catch ꡬ쑰 제거 μ „μ—­ ν•Έλ“€λŸ¬μ—μ„œ 였λ₯˜μ²˜λ¦¬
μœ μ €μ˜ Setting 개수 3개둜 μ œν•œν•˜λŠ” 둜직 μΆ”κ°€

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/service/SettingService.java (1)

61-83: Setting μ—”ν‹°ν‹° μ €μž₯ λˆ„λ½ 문제 (쀑볡 이슈)

μ„€μ • μ œν•œ 둜직 μΆ”κ°€λŠ” 쒋은 κ°œμ„ μ‚¬ν•­μž…λ‹ˆλ‹€. ν•˜μ§€λ§Œ 이전 λ¦¬λ·°μ—μ„œ μ§€μ λœ Setting μ—”ν‹°ν‹° μ €μž₯ λˆ„λ½ λ¬Έμ œκ°€ μ—¬μ „νžˆ μ‘΄μž¬ν•©λ‹ˆλ‹€. setting.getId()λ₯Ό λ°˜ν™˜ν•˜λ €λ©΄ λ¨Όμ € μ—”ν‹°ν‹°κ°€ μ €μž₯λ˜μ–΄μ•Ό ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•˜μ„Έμš”:

 setting.setUser(user);
+
+settingRepository.save(setting);

 saveSettingKeyword(settingDTO, setting);
πŸ“œ Review details

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between d9a401f and ab9f096.

πŸ“’ Files selected for processing (4)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/HotTopic_Description (1 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/Controller/SettingController.java (3 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/service/SettingService.java (4 hunks)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Global/Exception/GlobalExceptionHandler.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/HotTopic/HotTopic_Description
  • SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/Controller/SettingController.java
πŸ”‡ Additional comments (3)
SpringBoot/src/main/java/Baemin/News_Deliver/Global/Exception/GlobalExceptionHandler.java (1)

46-54: μ½”λ“œ μŠ€νƒ€μΌ κ°œμ„  승인

SettingException ν•Έλ“€λŸ¬μ˜ μ½”λ“œ ν¬λ§·νŒ…μ΄ κ°œμ„ λ˜μ–΄ 가독성이 ν–₯μƒλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/service/SettingService.java (2)

95-122: λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜ κ°„μ†Œν™” 승인

ResponseEntity λ°˜ν™˜ νƒ€μž…μ„ void둜 λ³€κ²½ν•˜μ—¬ λ©”μ„œλ“œκ°€ κ°„μ†Œν™”λ˜μ—ˆμŠ΅λ‹ˆλ‹€. κΆŒν•œ 체크 둜직과 λ‘œκΉ… λ©”μ‹œμ§€λ„ 적절히 μœ μ§€λ˜κ³  κ°œμ„ λ˜μ—ˆμŠ΅λ‹ˆλ‹€.


156-177: μ†Œν”„νŠΈ μ‚­μ œ 둜직 κ°œμ„  승인

λ©”μ„œλ“œ μ‹œκ·Έλ‹ˆμ²˜κ°€ κ°„μ†Œν™”λ˜κ³  λ‘œκΉ… λ©”μ‹œμ§€κ°€ κ°œμ„ λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ†Œν”„νŠΈ μ‚­μ œ 둜직이 적절히 μœ μ§€λ˜μ–΄ 데이터 무결성이 보μž₯λ©λ‹ˆλ‹€.

Comment on lines +12 to +15
import org.springframework.web.bind.annotation.RestControllerAdvice;

@ControllerAdvice
@RestControllerAdvice

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

쀑볡 μ–΄λ…Έν…Œμ΄μ…˜ μ‚¬μš© 제거 ν•„μš”

@ControllerAdvice와 @RestControllerAdviceλ₯Ό λ™μ‹œμ— μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. @RestControllerAdviceλŠ” @ControllerAdvice + @ResponseBody의 μ‘°ν•©μ΄λ―€λ‘œ ν•˜λ‚˜λ§Œ μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•˜μ„Έμš”:

-@ControllerAdvice
-@RestControllerAdvice
+@RestControllerAdvice
πŸ“ 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
import org.springframework.web.bind.annotation.RestControllerAdvice;
@ControllerAdvice
@RestControllerAdvice
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
// ...
}
πŸ€– Prompt for AI Agents
In
SpringBoot/src/main/java/Baemin/News_Deliver/Global/Exception/GlobalExceptionHandler.java
around lines 12 to 15, remove the redundant @ControllerAdvice annotation and
keep only @RestControllerAdvice, since @RestControllerAdvice already includes
@ControllerAdvice and @ResponseBody functionality.

Comment on lines +221 to +228
/**
* μ‚¬μš©μžμ˜ ν™œμ„±μ€‘μΈ 섀정이 3κ°œκ°€ λ„˜λŠ”μ§€ μ•„λ‹Œμ§€ κ²€μ‚¬ν•˜λŠ” λ©”μ„œλ“œ (λ‚΄λΆ€ λ©”μ„œλ“œ)
* */
private boolean isSettingLimitExceeded(User user) {
List<Setting> settingList = settingRepository.findActiveSettings(user, LocalDateTime.now());

return settingList.size() > 3;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

μ„€μ • μ œν•œ 둜직 였λ₯˜ μˆ˜μ • ν•„μš”

λ©”μ„œλ“œλͺ…은 isSettingLimitExceededμ΄μ§€λ§Œ μ‹€μ œ λ‘œμ§μ€ > 3으둜 λ˜μ–΄ μžˆμ–΄ 4κ°œκΉŒμ§€ ν—ˆμš©λ©λ‹ˆλ‹€. 3개 μ œν•œμ„ μ˜λ„ν–ˆλ‹€λ©΄ >= 3 쑰건을 μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

λ‹€μŒκ³Ό 같이 μˆ˜μ •ν•˜μ„Έμš”:

-        return settingList.size() > 3;
+        return settingList.size() >= 3;

λ˜λŠ” λ©”μ„œλ“œ λ¬Έμ„œν™”λ₯Ό λͺ…ν™•νžˆ ν•˜μ„Έμš”:

     /**
-     * μ‚¬μš©μžμ˜ ν™œμ„±μ€‘μΈ 섀정이 3κ°œκ°€ λ„˜λŠ”μ§€ μ•„λ‹Œμ§€ κ²€μ‚¬ν•˜λŠ” λ©”μ„œλ“œ (λ‚΄λΆ€ λ©”μ„œλ“œ)
+     * μ‚¬μš©μžμ˜ ν™œμ„±μ€‘μΈ 섀정이 3개 이상인지 κ²€μ‚¬ν•˜λŠ” λ©”μ„œλ“œ (λ‚΄λΆ€ λ©”μ„œλ“œ)
      * */
πŸ“ 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
/**
* μ‚¬μš©μžμ˜ ν™œμ„±μ€‘μΈ 섀정이 3κ°œκ°€ λ„˜λŠ”μ§€ μ•„λ‹Œμ§€ κ²€μ‚¬ν•˜λŠ” λ©”μ„œλ“œ (λ‚΄λΆ€ λ©”μ„œλ“œ)
* */
private boolean isSettingLimitExceeded(User user) {
List<Setting> settingList = settingRepository.findActiveSettings(user, LocalDateTime.now());
return settingList.size() > 3;
}
/**
* μ‚¬μš©μžμ˜ ν™œμ„±μ€‘μΈ 섀정이 3개 이상인지 κ²€μ‚¬ν•˜λŠ” λ©”μ„œλ“œ (λ‚΄λΆ€ λ©”μ„œλ“œ)
* */
private boolean isSettingLimitExceeded(User user) {
List<Setting> settingList = settingRepository.findActiveSettings(user, LocalDateTime.now());
return settingList.size() >= 3;
}
πŸ€– Prompt for AI Agents
In
SpringBoot/src/main/java/Baemin/News_Deliver/Domain/Mypage/service/SettingService.java
around lines 221 to 228, the method isSettingLimitExceeded currently returns
true only if the active settings count is greater than 3, allowing 4 active
settings. To enforce a 3-setting limit as intended, change the condition to use
>= 3 instead of > 3. Alternatively, update the method documentation to clearly
state the current behavior if you want to keep the logic as is.

@passionryu
passionryu merged commit 728ec42 into dev Jul 18, 2025
1 check passed
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.

2 participants