Skip to content

[Feat] 장소 설명 자동 생성 및 재시도 구현 - #437

Merged
yangjiae12 merged 7 commits into
developfrom
feat/431-place-overview
Nov 3, 2026
Merged

yangjiae12 merged 7 commits into
developfrom
feat/431-place-overview

Conversation

@yangjiae12

@yangjiae12 yangjiae12 commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

📌 PR 설명

장소 저장 후 외부 API를 통해 장소 설명을 자동으로 생성하고 저장하도록 연결했습니다.

  • TourAPI 설명을 우선 사용하고, 설명이 없으면 장소 일치 검증을 통과한 Gemini 설명을 사용합니다.
  • PENDING 상태의 장소를 스케줄러로 처리하여 신규, 기존 장소의 설명을 비동기로 생성합니다.
  • 생성 실패 시 최초 시도 1회와 재시도 1회를 포함해 최대 2회 처리하며, 시도 시작 시점으로부터 5분 후 재시도합니다.
  • 장소 설명, 출처, 처리 상태 및 시도 이력을 저장하는 컬럼과 조회 인덱스를 추가했습니다.

🔗 연관된 이슈

Resolves: #431

📝 리뷰 요구사항

  • 외부 API 호출과 상태 저장의 트랜잭션 분리가 적절한지 확인 부탁드립니다.
  • 재시도 횟수, 간격과 스케줄러 설정을 확인 부탁드립니다.

💻 테스트 결과

  • API 테스트 완료
  • 정상 동작 확인
overview 생성 확인
image
등록 API 수정 API
image image

Summary by CodeRabbit

  • New Features
    • Place overviews are now retrieved and saved automatically, using verified available sources.
    • Failed or unavailable lookups can be retried automatically, with a limit on attempts.
  • Bug Fixes
    • Changes to a place’s name, address, or coordinates reset its overview so it can be refreshed.
    • Existing place details are preserved when updates omit values, and equivalent coordinate values no longer trigger unnecessary resets.

@yangjiae12 yangjiae12 self-assigned this Nov 2, 2026
@yangjiae12 yangjiae12 linked an issue Nov 2, 2026 that may be closed by this pull request
4 tasks
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 21 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f63143fa-8c26-4880-81de-0c8b9995c438
Commits

Reviewing files that changed from the base of the PR and between 24e9af8 and d5cc7c2.

Files selected for processing: 11
  • src/main/java/com/yeogido/backend/domain/content/client/TourApiClient.java
  • src/main/java/com/yeogido/backend/domain/place/entity/Place.java
  • src/main/java/com/yeogido/backend/domain/place/repository/PlaceRepository.java
  • src/main/java/com/yeogido/backend/domain/place/service/PlaceServiceImpl.java
  • src/main/java/com/yeogido/backend/domain/placeenrichment/scheduler/PlaceOverviewRetryScheduler.java
  • src/main/java/com/yeogido/backend/domain/placeenrichment/service/PlaceOverviewEnrichmentServiceImpl.java
  • src/main/resources/application.yml
  • src/test/java/com/yeogido/backend/domain/place/repository/PlaceOverviewRetryRepositoryTest.java
  • src/test/java/com/yeogido/backend/domain/place/service/PlaceOverviewWriteIntegrationTest.java
  • src/test/java/com/yeogido/backend/domain/placeenrichment/scheduler/PlaceOverviewRetrySchedulerTest.java
  • src/test/java/com/yeogido/backend/domain/placeenrichment/service/PlaceOverviewEnrichmentServiceTest.java
Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: a6aecd1f-7ff8-43b1-b15f-bd97fd321406
Commits

Reviewing files that changed from the base of the PR and between c65a140 and 24e9af8.

Files selected for processing: 19
  • src/main/java/com/yeogido/backend/domain/place/entity/Place.java
  • src/main/java/com/yeogido/backend/domain/place/enums/PlaceOverviewStatus.java
  • src/main/java/com/yeogido/backend/domain/place/repository/PlaceRepository.java
  • src/main/java/com/yeogido/backend/domain/place/service/PlaceServiceImpl.java
  • src/main/java/com/yeogido/backend/domain/placeenrichment/scheduler/PlaceOverviewPendingScheduler.java
  • src/main/java/com/yeogido/backend/domain/placeenrichment/scheduler/PlaceOverviewRetryScheduler.java
  • src/main/java/com/yeogido/backend/domain/placeenrichment/service/PlaceOverviewEnrichmentService.java
  • src/main/java/com/yeogido/backend/domain/placeenrichment/service/PlaceOverviewEnrichmentServiceImpl.java
  • src/main/java/com/yeogido/backend/domain/placeenrichment/service/TourRegionCodeMapper.java
  • src/main/resources/application.yml
  • src/main/resources/db/migration/V41__add_place_overview.sql
  • src/main/resources/db/migration/V42__add_place_overview_retry.sql
  • src/test/java/com/yeogido/backend/domain/place/migration/PlaceOverviewRetryMigrationTest.java
  • src/test/java/com/yeogido/backend/domain/place/repository/PlaceOverviewRetryRepositoryTest.java
  • src/test/java/com/yeogido/backend/domain/place/service/PlaceOverviewWriteIntegrationTest.java
  • src/test/java/com/yeogido/backend/domain/placeenrichment/scheduler/PlaceOverviewPendingSchedulerTest.java
  • src/test/java/com/yeogido/backend/domain/placeenrichment/scheduler/PlaceOverviewRetrySchedulerTest.java
  • src/test/java/com/yeogido/backend/domain/placeenrichment/service/PlaceOverviewEnrichmentServiceTest.java
  • src/test/java/com/yeogido/backend/domain/placeenrichment/service/TourRegionCodeMapperTest.java

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

The PR adds overview fields and retry state to places, enriches eligible records through Tour and Gemini services, and schedules pending and failed records for processing. Place updates reset overview state when relevant place details change.

Changes: Place Overview Enrichment

Layer / File(s) Summary
Overview state and place writes
src/main/java/com/yeogido/backend/domain/place/entity/Place.java, src/main/java/com/yeogido/backend/domain/place/enums/PlaceOverviewStatus.java, src/main/java/com/yeogido/backend/domain/place/service/PlaceServiceImpl.java, src/main/resources/db/migration/V41__add_place_overview.sql, src/main/resources/db/migration/V42__add_place_overview_retry.sql, src/test/java/com/yeogido/backend/domain/place/migration/PlaceOverviewRetryMigrationTest.java, src/test/java/com/yeogido/backend/domain/place/service/PlaceOverviewWriteIntegrationTest.java
Place records gain overview content, source, status, and retry fields. Course and content writes update existing place details and reset enrichment state when relevant details change. Migrations and integration tests cover these fields and write behavior.
Enrichment and result persistence
src/main/java/com/yeogido/backend/domain/place/repository/PlaceRepository.java, src/main/java/com/yeogido/backend/domain/placeenrichment/service/PlaceOverviewEnrichmentService.java, src/main/java/com/yeogido/backend/domain/placeenrichment/service/PlaceOverviewEnrichmentServiceImpl.java, src/main/java/com/yeogido/backend/domain/placeenrichment/service/TourRegionCodeMapper.java, src/test/java/com/yeogido/backend/domain/placeenrichment/service/*
The enrichment service claims places, checks Tour results before verified Gemini results, and persists results for the current attempt. Region-code resolution uses separate transactions around database reads and writes.
Scheduled pending and retry processing
src/main/java/com/yeogido/backend/domain/place/repository/PlaceRepository.java, src/main/java/com/yeogido/backend/domain/placeenrichment/scheduler/*, src/main/resources/application.yml, src/test/java/com/yeogido/backend/domain/place/repository/PlaceOverviewRetryRepositoryTest.java, src/test/java/com/yeogido/backend/domain/placeenrichment/scheduler/*
Repository queries return eligible pending and retryable place IDs. Configured scheduled jobs process each result independently and continue after a per-place runtime exception.

Estimated code review effort: 4 (Complex) | ~55 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant Scheduler as Pending or retry scheduler
  participant Repository as PlaceRepository
  participant Enrichment as PlaceOverviewEnrichmentServiceImpl
  participant Tour as TourPlaceEnrichmentService
  participant Gemini as GeminiPlaceEnrichmentService
  Scheduler->>Repository: Query eligible place IDs
  Scheduler->>Enrichment: Enrich each place ID
  Enrichment->>Repository: Lock and claim place
  Enrichment->>Tour: Retrieve Tour overview
  alt Tour overview is not usable
    Enrichment->>Gemini: Retrieve Gemini overview
  end
  Enrichment->>Repository: Save result for current attempt
Loading

Possibly related PRs

  • yeogido/backend#425: Adds the Gemini enrichment service and verified-result handling used by this PR.
  • yeogido/backend#414: Adds Tour enrichment contracts and region mapping used by this PR.

Suggested reviewers: seoyeon-park0103

Merge Risk: High · previous review 24e9a

Requests can change place details and descriptions shared by other users, while interrupted enrichment can remain stuck. Protect shared place data and restore recovery before merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 3.70% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed 제목은 장소 설명 자동 생성과 재시도 구현이라는 변경의 핵심을 명확하고 간결하게 설명합니다.
Linked Issues check Passed Directly linked issue #431 has four coding requirements. Each is supported by the PR summary and the reviewed code evidence.

1. [#431] TourAPI first, then Gemini fallback. PlaceOverviewEnrichmentServ…
Out of Scope Changes check Passed All changed areas support the overview enrichment objective of #431.

- Place entity, PlaceOverviewStatus enum, V41 and V42 migrations: store overview state and source. Required by #431.
- PlaceReposi…
Description check Passed The pull request description includes all required sections: change summary, linked issue, review requirements, and test results. It clearly describes the overview enrichment flow, retry policy, trans…
Full details: Linked Issues check

Explanation

Directly linked issue #431 has four coding requirements. Each is supported by the PR summary and the reviewed code evidence.

  1. [#431] TourAPI first, then Gemini fallback. PlaceOverviewEnrichmentServiceImpl uses a matched Tour API overview first. It accepts a nonblank Gemini overview only when its match status is VERIFIED. Otherwise it marks NO_OVERVIEW.
  2. [#431] Store overview and source per place. Place gains overview, overviewSource, and overviewStatus fields. V41 and V42 migrations add the matching columns and an index.
  3. [#431] Treat new or overview-less places as enrichment targets on create and update. New places default to PENDING. PlaceServiceImpl.getOrCreatePlace now calls updatePlace for existing places on both overloads. Place.updateTourData resets overview state when name, address, or coordinates change. PlaceRepository pending candidates select PENDING places with null or blank overview. Existing rows migrate to PENDING, so they become candidates.
  4. [#431] Asynchronous enrichment after save, without affecting create or update. External calls run in the PlaceOverviewPendingScheduler and PlaceOverviewRetryScheduler flows, not in the create or update request. Enrichment runs in REQUIRES_NEW transactions. Per-place RuntimeException is caught and logged.

Limitation: places already in NO_OVERVIEW are not re-targeted when linked again without metadata changes. This is a design choice of the terminal no-overview state. It is not a coding requirement of #431 as written.

The review relied on the PR summary and one focused diff of PlaceServiceImpl. The new tests were not executed during this review.

Full details: Out of Scope Changes check

Explanation

All changed areas support the overview enrichment objective of #431.

  • Place entity, PlaceOverviewStatus enum, V41 and V42 migrations: store overview state and source. Required by #431.
  • PlaceRepository lookup and candidate queries: select pending and retryable places. Required by #431.
  • PlaceServiceImpl updatePlace and getOrCreatePlace changes: mark places for enrichment on create and update. Required by #431.
  • PlaceOverviewPendingScheduler, PlaceOverviewRetryScheduler, PlaceOverviewEnrichmentService(Impl), application.yml: run asynchronous enrichment and retries. Required by #431.
  • TourRegionCodeMapper transaction split and TourRegionCodeMapperTest update: remove class-wide transaction so that external region-code calls run outside transactions. Supports the enrichment transaction design needed by #431.
  • Tests (migration, repository, write integration, scheduler, enrichment service, region mapper): verify the changes above. Supporting tests are in scope.

No unrelated change was found in the summary.

Full details: Description check

Explanation

The pull request description includes all required sections: change summary, linked issue, review requirements, and test results. It clearly describes the overview enrichment flow, retry policy, transaction separation, and completed tests.

Full details: Docstring Coverage

Explanation

Docstring coverage is 3.70% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 27 functions across 16 files. (3 skipped: 3 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

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

  • Fix comments: Fix CodeRabbit comments on this PR

@chans20 chans20 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

예약 작업 스레드 설정이 없어 기본 1개로 돌 것 같습니다. 설명 생성 배치가 길어지면 정각 랭킹 갱신과 04시 동기화가 혹시나 그만큼 늦게 실행될 수 있으니, 풀 크기 설정이나 전용 스레드 검토 부탁드립니닷

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

TOUR API 값이 8자리 이상이면 좌표가 같아도 바뀐 것으로 판단해서, 동기화 때마다 설명이 지워지고 다시 생성될 것 같습니다. 비교 전에 setScale(7, RoundingMode.HALF_UP)으로 자릿수를 맞추면 좋을것같습니다.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

확인해보니 API 원본과 DB에 저장된 좌표의 소수점 정밀도가 달라서, 같은 좌표인데도 설명이 초기화되는 문제가 재현됐습니다. 말씀해주신 대로 소수점 7자리로 반올림해서 저장하도록 수정했고, 동일 좌표에서는 설명이 유지되는 테스트까지 확인했습니다. 꼼꼼한 리뷰 감사합니다!

@yangjiae12

Copy link
Copy Markdown
Member Author

말씀해주신 대로 기본 스레드 1개를 공유하고 있어서, 설명 생성 및 재시도를 전용 스케줄러로 분리했고, 설명 배치가 대기 중이어도 기본 예약 작업이 실행되는 테스트까지 확인했습니다. 리뷰 감사합니다!

@chans20 chans20 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

수고하셨습니다~

@yangjiae12
yangjiae12 merged commit 11a44ed into develop Nov 3, 2026
2 checks 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.

[FEAT] 코스 등록 및 수정 시 장소 정보 저장 로직 구현

2 participants