Skip to content

feat: AI 가정통신문 전체 분석 응답 저장 연동#64

Merged
deli-minju merged 3 commits into
developfrom
feat/#63-newsletter-analyze-save
May 24, 2026
Merged

feat: AI 가정통신문 전체 분석 응답 저장 연동#64
deli-minju merged 3 commits into
developfrom
feat/#63-newsletter-analyze-save

Conversation

@deli-minju
Copy link
Copy Markdown
Contributor

@deli-minju deli-minju commented May 24, 2026

📌 작업 요약

  • 요약:
    • BE 가정통신문 파이프라인의 AI 호출 경로를 /ai/newsletters/extract-items에서 /ai/newsletters/analyze로 전환
    • AI 서버 응답의 title, summary, items를 BE 저장 흐름에 반영
    • AI 응답의 items는 기존 checklist 저장 로직에 연결
    • AI 응답의 title, summary가 비어 있을 경우 기존 BE fallback 로직을 사용하도록 처리
    • /analyze 연동 저장 정책 문서 추가
  • 관련 이슈: closes [FEAT] BE 가정통신문 전체 분석 응답 저장 연동 #63

🌿 브랜치 정보

  • Source: feat/#63-newsletter-analyze-save
  • Target: develop (기본)

✅ 체크리스트

  • 브랜치 컨벤션 준수 (feat/refac/hotfix/chore/design/bugfix)
  • 커밋 컨벤션 준수 (feat/fix/refactor/docs/style/chore)
  • self-review 완료
  • 테스트 및 로컬 실행 확인 완료

🧪 테스트 결과

PS C:\Users\mjmdm\IdeaProjects\GACHI-BE> .\gradlew.bat --no-daemon test --tests com.gachi.be.domain.newsletter.pipeline.AiNewsletterClientTest --tests com.gachi.be.domain.newsletter.pipeline.NewsletterAiAnalyzerTest

BUILD SUCCESSFUL

Summary by CodeRabbit

릴리스 노트

  • New Features

    • AI 분석을 통한 가정통신문 제목 및 요약 자동 생성 기능 추가
    • 향상된 항목 추출 및 날짜 인식 기능
  • Documentation

    • AI 분석 응답 저장 정책 및 연동 방식 문서화
  • Tests

    • AI 분석 기능 및 데이터 저장 흐름 검증 테스트 추가

Review Change Stack

@deli-minju deli-minju self-assigned this May 24, 2026
@deli-minju deli-minju added the feat 새로운 기능 추가 작업 label May 24, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

Warning

Review limit reached

@deli-minju, we couldn't start this review because you've used your available PR reviews for now.

Your plan currently allows 1 review/hour. Refill in 10 minutes and 37 seconds.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more review capacity refills, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than trial, open-source, and free plans. In all cases, review capacity refills continuously over time.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0f5afd74-e487-4973-8d48-0d237e7ed181

📥 Commits

Reviewing files that changed from the base of the PR and between 225f575 and aefbcde.

📒 Files selected for processing (5)
  • deploy/.env.example
  • deploy/docker-compose.yml
  • src/main/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzer.java
  • src/test/java/com/gachi/be/domain/newsletter/pipeline/AiNewsletterClientTest.java
  • src/test/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzerTest.java
📝 Walkthrough

Walkthrough

AI 뉴스레터 분석 파이프라인이 기존 extractItems 중심 흐름에서 analyze 중심으로 전환되었다. 응답 계약이 AnalysisResponse로 확장되어 제목, 요약, 항목, 메타데이터를 함께 처리하며, 제목/요약 정규화와 폴백 로직이 추가되어 통합된다.

Changes

AI Newsletter Analyze API Integration

Layer / File(s) Summary
Response Model and Contract Updates
src/main/java/com/gachi/be/domain/newsletter/pipeline/AiNewsletterClient.java
AnalysisRequest, AnalysisResponse, SelectedDateCandidate 레코드가 정의되고, ExtractedItemselectedDateCandidate 필드가 추가되어 새 API 계약을 확립한다.
Client Implementation - Analyze Endpoint
src/main/java/com/gachi/be/domain/newsletter/pipeline/AiNewsletterClient.java
analyze(...) 공개 메서드가 /ai/newsletters/analyze 엔드포인트를 호출하도록 구현되며, 응답을 AnalysisResponse로 역직렬화하고 normalized()items null을 빈 리스트로 보정해 반환한다.
Analyzer Integration and Title/Summary Normalization
src/main/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzer.java
NewsletterAiAnalyzerAnalysisResponse를 소비하도록 업데이트되며, normalizeTitle(), normalizeSummary() 메서드를 통해 AI 응답을 컴팩트하고, 제목은 없을 때 원문 기반 추론으로, 요약은 없을 때 translated/원문 중 선택해 폴백한다.
Client API Tests
src/test/java/com/gachi/be/domain/newsletter/pipeline/AiNewsletterClientTest.java
로컬 HttpServer/ai/newsletters/analyze 엔드포인트를 모킹하여 요청 경로/본문 캡처 및 AnalysisResponse 파싱, title/summary/items 개수 검증을 수행한다.
Analyzer Integration Tests
src/test/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzerTest.java
AI 분석 응답 사용, title/summary 정규화, 폴백 동작(AI 제목이 공백일 때 원문에서 추출), checklistRepository.saveAll() 호출 및 저장 필드 검증을 테스트한다.
Integration Documentation
docs/newsletter-ai-analyze-integration.md
/ai/newsletters/analyze 호출 위치, title/summary 저장 매핑, items 체크리스트 연결, meta 미저장, 폴백 규칙, AI 장애 시 상태 전환 및 호환성 방침을 명시한다.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GACHI-Project/GACHI-BE#59: AiNewsletterClient 도입으로 AI 서버 extract-items 호출을 옮긴 이전 작업의 직접 연장선으로, 동일 클래스/도메인 파이프라인의 API 전환을 이룬다.
  • GACHI-Project/GACHI-BE#46: 메인 PR이 List<NewsletterDateCandidate>SelectedDateCandidate 저장 스키마를 사용하는데, 이는 해당 PR의 OCR 후 날짜 후보 추출 및 저장 구현과 데이터 흐름을 함께 이룬다.
  • GACHI-Project/GACHI-BE#41: NewsletterAiAnalyzer.analyze(...) 메서드 시그니처 확장 및 AI 분석 흐름 리팩터링이 공통으로 이루어져, 같은 파이프라인 통합의 일부이다.

Suggested reviewers

  • Hminkyung
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 핵심 변경사항인 AI 전체 분석 응답 저장 연동을 명확하고 간결하게 요약하고 있습니다.
Description check ✅ Passed PR 설명이 템플릿의 필수 섹션을 모두 포함하고 있으며, 작업 요약, 이슈 연결, 브랜치 정보, 체크리스트, 테스트 결과가 완벽하게 기입되어 있습니다.
Linked Issues check ✅ Passed PR의 코드 변경이 이슈 #63의 모든 주요 요구사항을 충족합니다: /ai/newsletters/analyze 호출 전환, title/summary/items 응답 DTO 반영, fallback 로직 구현, checklist 저장 연결, 테스트 추가 완료.
Out of Scope Changes check ✅ Passed PR의 모든 변경사항이 이슈 #63의 요구사항 범위 내에 있으며, 추가적인 범위 외 변경은 발견되지 않습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#63-newsletter-analyze-save

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

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@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: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/main/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzer.java`:
- Around line 43-47: Remove the redundant null-check for items in
NewsletterAiAnalyzer: since AiNewsletterClient.analyze(...) already calls
normalized() and guarantees AnalysisResponse.items() is non-null, replace the
conditional assignment of items with a direct use of analysisResponse.items()
(keep the variable name items if needed) and remove the ternary null fallback;
update any code that relied on the previous fallback accordingly so
NewsletterAiAnalyzer relies on the normalized contract from
AiNewsletterClient.analyze().

In
`@src/test/java/com/gachi/be/domain/newsletter/pipeline/AiNewsletterClientTest.java`:
- Around line 20-84: Add three negative tests to AiNewsletterClientTest that
exercise AiNewsletterClient.analyze's error paths: (1) simulate the AI server
returning a 500 response and assert analyze throws ExternalApiException with
ErrorCode.EXTERNAL_API_ERROR (or equivalent), (2) simulate a delayed response
that exceeds properties.connect/read timeout to assert analyze throws
ExternalApiException for timeouts, and (3) return a 200 status with malformed
JSON and assert analyze throws ExternalApiException for parse errors; reuse the
existing HttpServer setup and AiServerProperties to point to the test server,
and tear down server/executor in finally blocks as in the existing
analyzeCallsAnalyzeEndpointAndParsesTitleSummaryItems test.

In
`@src/test/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzerTest.java`:
- Around line 81-103: Add two unit tests in NewsletterAiAnalyzerTest to cover
partial-fallback scenarios: one where aiNewsletterClient.analyze returns a
non-blank title and blank summary, and one where it returns a blank title and
non-blank summary. Use the same setup as
analyzeFallsBackWhenAiTitleSummaryAreBlank (mock newsletterRepository.findById
and aiNewsletterClient.analyze) but return AnalysisResponse with only title or
only summary populated; then call newsletterAiAnalyzer.analyze and assert
AiAnalysisResult.title()/summary() fall back to the original inputs when the AI
value is blank while accepting the AI-provided value when present, and verify
checklistRepository.saveAll is never called. Reference symbols:
NewsletterAiAnalyzerTest, newsletterAiAnalyzer.analyze,
aiNewsletterClient.analyze, AnalysisResponse, AiAnalysisResult,
checklistRepository.saveAll.
- Line 95: In NewsletterAiAnalyzerTest update the mocked AnalysisResponse
returned in the .thenReturn(...) call so title and summary use the same
empty-case for consistency (e.g., both "" or both " "), or split into two tests
verifying each empty-case separately; target the mocked return construction of
new AnalysisResponse(...) in the test to ensure the fallback/normalization
behavior of NewsletterAiAnalyzer is validated against a single, consistent
empty-value scenario (or add a second test that uses the alternate empty-value).
- Around line 69-70: Remove the local unchecked captor and the
`@SuppressWarnings`; instead declare a generic, type-safe captor as a field using
Mockito's `@Captor`: add a field like "private `@Captor`
ArgumentCaptor<List<Checklist>> captor" in NewsletterAiAnalyzerTest and ensure
mocks are initialized in the test setup (e.g.,
MockitoAnnotations.openMocks(this) or `@ExtendWith`(MockitoExtension.class)) so
the captor is injected and you avoid raw types and unchecked warnings when
capturing arguments.
- Around line 73-78: The test in NewsletterAiAnalyzerTest currently asserts only
content/detail for the saved Checklist; extend it to verify the time-related
fields from the source ExtractedItem (datetime, timezone, dateStatus,
confidence) are correctly mapped and stored. After capturing savedItems
(captor.getValue()), add assertions on savedItems.get(0) to compare its
datetime, timezone, dateStatus and confidence properties against the expected
values used when constructing the ExtractedItem in the test setup so the mapping
from ExtractedItem -> Checklist is validated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: b8f7cfdd-7f8c-4298-b277-423ebd4133e3

📥 Commits

Reviewing files that changed from the base of the PR and between c6b6c4f and 225f575.

📒 Files selected for processing (5)
  • docs/newsletter-ai-analyze-integration.md
  • src/main/java/com/gachi/be/domain/newsletter/pipeline/AiNewsletterClient.java
  • src/main/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzer.java
  • src/test/java/com/gachi/be/domain/newsletter/pipeline/AiNewsletterClientTest.java
  • src/test/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzerTest.java

Comment thread src/main/java/com/gachi/be/domain/newsletter/pipeline/NewsletterAiAnalyzer.java Outdated
@deli-minju deli-minju requested a review from Hminkyung May 24, 2026 12:23
Copy link
Copy Markdown
Collaborator

@Hminkyung Hminkyung left a comment

Choose a reason for hiding this comment

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

AI 호출경로 변경한 부분부터 자세하게 작성한것까지 전부 확인 완료했씁니당!!
고생하셨써요~~~

@deli-minju deli-minju merged commit 79d16a0 into develop May 24, 2026
3 checks passed
@deli-minju deli-minju deleted the feat/#63-newsletter-analyze-save branch May 24, 2026 12:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 새로운 기능 추가 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] BE 가정통신문 전체 분석 응답 저장 연동

2 participants