wish 응답에 출처 커머스몰 표시명(sourcePlatform) 추가#767
Conversation
- firebase-admin 이 전이로 끌고 오지만 InternetDomainName(PSL)을 직접 쓰게 되어 명시 선언으로 승격 - 전이 제공자가 Guava 를 떨구면 조용히 깨진다 - Maven Central 최신 안정 33.6.0-jre (Spring Boot BOM 미관리)
- WishItemResponse.ItemView·WishPriceHistoryResponse 에 sourcePlatform(nullable) 추가 - 백오피스 등록값이 있으면 그 표기, 없으면 URL host 에서 유도한 임시값, 이미지 등록 item 은 null - items 컬럼 저장 대신 조회 시 유도로 결정 - 컬럼 저장안은 기존 행 백필 + 매핑 추가 때마다 재백필이 필요해, 백오피스 수정이 과거 item 에 즉시 소급되는 유도안을 택했다 - source_platforms(domain PK, display_name) 테이블 + DbSourcePlatformResolver(@volatile 캐시·도메인 최장 일치·afterCommit/주기 reload) - DbExtractionRoutingPolicy 패턴 재사용, 시드 없음(정식 표기는 백오피스가 등록) - 백오피스 /admin/source-platforms 목록·상세 CRUD + SOURCE_PLATFORM_UPDATE 감사 기록 - fallback 은 왼쪽 라벨 휴리스틱 대신 PSL(Guava InternetDomainName) 채택 - 기능성 서브도메인(global.oliveyoung.com 등)에서 왼쪽 라벨이 더 자주 틀린다. co.kr 2단 suffix·호스팅 suffix(github.io)는 정확히 나오고, PSL 에 없는 임의 다단 도메인은 suffix 앞 라벨로 떨어지는 한계를 단위 테스트로 고정 - host 정규형은 ProductLink.normalizedHost() 로 승격해 matchesAnyDomain 과 공유
|
Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (2)
Walkthrough도메인별 출처 플랫폼 표시명 레지스트리와 관리자 CRUD를 추가하고, 메모리 캐시 및 PSL fallback으로 표시명을 결정한다. 결정된 값은 위시 항목과 가격 이력 응답의 Changes출처 플랫폼 표시명 기능
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant WishlistController
participant DbSourcePlatformResolver
participant SourcePlatformJpaRepository
participant SourcePlatformFallback
participant WishItemResponse
Client->>WishlistController: 위시 요청
WishlistController->>DbSourcePlatformResolver: 상품 링크 표시명 조회
DbSourcePlatformResolver->>SourcePlatformJpaRepository: 플랫폼 데이터 로드 및 캐시
DbSourcePlatformResolver->>SourcePlatformFallback: 미등록 도메인 fallback 요청
SourcePlatformFallback-->>DbSourcePlatformResolver: PSL 기반 표시명
DbSourcePlatformResolver-->>WishlistController: sourcePlatform
WishlistController->>WishItemResponse: 응답 생성
WishItemResponse-->>Client: sourcePlatform 포함 응답
Assessment against linked issues
🚥 Pre-merge checks | ✅ 1 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (1 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformService.kt`:
- Around line 102-107: Update reloadAfterCommit and the SourcePlatformResolver
refresh flow to publish a cluster-wide cache invalidation after the transaction
commits, using the project’s existing Redis pub/sub or message-broker mechanism
so every instance reloads immediately. If no such mechanism exists, change the
admin UI/API messaging and documented expectation from immediate application to
propagation within the resolver’s 300-second refresh interval.
- Around line 80-89: Update normalize so domain validation also parses the
normalized value as a host and requires the parsed URI host to exactly equal the
normalized input. Reject values such as query-bearing domains and
consecutive-label domains with the existing IllegalArgumentException flow, while
preserving the current trimming, lowercasing, and user-facing validation
messages where applicable.
In
`@src/test/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformIntegrationTest.kt`:
- Around line 55-145: Add a test near the existing source-platform resolver
integration tests that registers both example.com and shop.example.com with
distinct display names, reloads the resolver, and asserts that resolving
m.shop.example.com returns the shop.example.com name. Clean up both entities in
finally and reload the resolver afterward, preserving the existing test
isolation pattern.
🪄 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.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: 2c6586a1-aa11-4bb8-9043-4bd66df09158
📒 Files selected for processing (22)
build.gradle.ktssrc/main/kotlin/com/depromeet/piki/admin/audit/AdminAuditAction.ktsrc/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformController.ktsrc/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformService.ktsrc/main/kotlin/com/depromeet/piki/product/domain/ProductLink.ktsrc/main/kotlin/com/depromeet/piki/product/source/SourcePlatformEntity.ktsrc/main/kotlin/com/depromeet/piki/product/source/SourcePlatformFallback.ktsrc/main/kotlin/com/depromeet/piki/product/source/SourcePlatformJpaRepository.ktsrc/main/kotlin/com/depromeet/piki/product/source/SourcePlatformResolver.ktsrc/main/kotlin/com/depromeet/piki/wishlist/controller/WishlistApiExamples.ktsrc/main/kotlin/com/depromeet/piki/wishlist/controller/WishlistController.ktsrc/main/kotlin/com/depromeet/piki/wishlist/controller/dto/WishItemResponse.ktsrc/main/kotlin/com/depromeet/piki/wishlist/controller/dto/WishPriceHistoryResponse.ktsrc/main/resources/db/migration/V20260719160822__create_source_platforms.sqlsrc/main/resources/templates/admin/index.htmlsrc/main/resources/templates/admin/source-platform-detail.htmlsrc/main/resources/templates/admin/source-platforms.htmlsrc/test/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformIntegrationTest.ktsrc/test/kotlin/com/depromeet/piki/product/source/SourcePlatformFallbackTest.ktsrc/test/kotlin/com/depromeet/piki/wishlist/controller/WishPriceHistoryIntegrationTest.ktsrc/test/kotlin/com/depromeet/piki/wishlist/controller/WishlistImagePresignedIntegrationTest.ktsrc/test/kotlin/com/depromeet/piki/wishlist/controller/WishlistRegisterAsyncIntegrationTest.kt
- brand.github.io → brand.myshopify.com (PSL private 섹션에 실재하는 커머스 호스팅 suffix, 커머스 도메인과 정합)
- muuusinsa.as.as.as.com("as") → brand.cafe24.com("cafe24") - PSL 미등재 호스팅 suffix 가 입점 브랜드 대신 호스팅사 라벨로 떨어지는 같은 한계를 실존 도메인으로 고정
- 교체 전 후보 host 들을 Guava 번들 PSL 로 실측해 확정 (cafe24.com 미등재·myshopify.com 등재 확인), SourcePlatformFallback 주석도 동기화
- example.com?preview=1, foo..example.com 같은 문자열이 기존 검증(스킴·경로·공백·점 검사)을 통과해 저장되면, 어떤 URL host 와도 매칭되지 않는 유령 행이 된다 - 운영 화면에선 저장 성공으로 보여 응답은 계속 fallback 이 나가는 함정 (CodeRabbit 지적 수용) - 정규화 후 URI host 파싱 결과가 입력과 정확히 일치할 때만 저장을 허용
- URL host 로 해석될 수 없는 도메인(쿼리 문자·빈 라벨)이 SSR 에러로 거부되고 저장되지 않는 것을 고정 (직전 fix 의 회귀 방지) - 부모/서브도메인 동시 등록 시 더 구체적인(긴) 도메인의 표시명이 이기고, 부모까지만 매칭되는 host 는 부모 표시명을 받는 최장 일치 규칙을 직접 단언 (CodeRabbit 지적 수용 - 기존 테스트는 단일 등록 도메인만 검증했다)
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformService.kt (1)
53-58: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win무결성 예외를 모두 ‘중복 저장’으로 변환하지 마세요.
DataIntegrityViolationException은 PK 중복 외에도 제약조건 위반을 포함할 수 있는데, 현재 구현은 모든 경우를 동시 저장 충돌로 오인하고 원인 예외도 버립니다. 스키마 제약이 추가되거나 예상치 못한 데이터 오류가 발생하면 잘못된 안내가 나가고 장애 원인 추적도 어려워집니다.DB에 맞는 duplicate-key 원인만 판별해
IllegalArgumentException으로 변환하고, 나머지는 원본 예외를 재전파하세요. 변환하는 경우에도 원인 예외를 cause로 보존하고, 중복 외 제약 위반 테스트를 추가하는 것이 안전합니다.As per path instructions, “API 안정성 — 예외→HTTP”와 “운영 리스크 — null/예외 처리”를 우선 검토했습니다.
🤖 Prompt for 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. In `@src/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformService.kt` around lines 53 - 58, Update the DataIntegrityViolationException handling around saveAndFlush in AdminSourcePlatformService so only a database-confirmed duplicate-key/primary-key violation is converted to IllegalArgumentException. Preserve the original exception as the cause of the converted exception, and rethrow all other integrity violations unchanged; add coverage for a non-duplicate constraint violation.Sources: Path instructions, Linters/SAST tools
🤖 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/test/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformIntegrationTest.kt`:
- Around line 85-100: Update the test `추가 폼은 URL host 로 해석될 수 없는 도메인을 거부한다` to
verify that no entity is created under any normalized key, not only the raw
input key. Capture the repository entity count before each request and assert it
is unchanged afterward, or compare `findAll()` results to ensure no new row was
added.
---
Outside diff comments:
In
`@src/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformService.kt`:
- Around line 53-58: Update the DataIntegrityViolationException handling around
saveAndFlush in AdminSourcePlatformService so only a database-confirmed
duplicate-key/primary-key violation is converted to IllegalArgumentException.
Preserve the original exception as the cause of the converted exception, and
rethrow all other integrity violations unchanged; add coverage for a
non-duplicate constraint violation.
🪄 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.yml
Review profile: CHILL
Plan: Pro Plus
Run ID: 4ebb61c1-3a1f-4576-9205-7334f251c25f
📒 Files selected for processing (2)
src/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformService.ktsrc/test/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformIntegrationTest.kt
- raw 키 findById 만으로는 입력이 정규화된 다른 키로 저장되는 경우를 못 잡는다 (CodeRabbit 지적 수용) - 요청 전후 count 비교로 "어떤 키로도 저장 없음"을 고정
|
@coderabbitai review body 의 outside-diff 지적(
|
|
Tip For best results, initiate chat on the files or code changes.
향후 ✏️ Learnings added
|
- 표시명 칸(.n)에 min-width 0 + max-width 45% + ellipsis + title 툴팁 - maxlength 255 표시명이 도메인 칸을 0 폭까지 밀고 행을 가로로 넘치게 하던 구조를 도메인 칸과 같은 규칙으로 정렬 (코드리뷰 반영) - 어드민 홈 lede 가 알림·공지만 언급해 카드 5개와 어긋나던 기존 드리프트를 이번 카드 추가에 맞춰 갱신
- 컨트롤러/OpenAPI 규약의 정당 예외 열거가 실제 코드와 어긋나면 컨벤션 점검이 미분류 위반으로 오인한다 (코드리뷰 반영)
Situation
Task
Action
설계 결정
저장 방식:
미등록 도메인의 임시 표시명(fallback) 규칙:
sourcePlatform, 테이블source_platforms. item 의 기존 컬럼(source_url·source_image_key)과 source_ 접두가 정렬되고, 추출 쪽 기존 어휘(extraction_platform_policies)와 platform 이 일치한다.구현
WishItemResponse.ItemView·WishPriceHistoryResponse에 sourcePlatform(nullable) 추가. 리졸버는 빈이라 컨트롤러가 판정을 풀어 DTO 의 from 에 넘긴다.source_platforms(domain PK, display_name) 테이블 +DbSourcePlatformResolver. @volatile 불변 리스트 캐시, 도메인 길이 내림차순 최장 일치, afterCommit·5분 주기 reload.DbExtractionRoutingPolicy패턴 재사용.SourcePlatformFallback이 GuavaInternetDomainName.topPrivateDomain()의 첫 라벨을 뽑는다. 도메인 문법이 아니면(IP 등) host 원형, 이미지 등록 item(URL 없음)은 null.ProductLink.normalizedHost()로 승격해 matchesAnyDomain 과 공유한다.AdminExtractionPolicyController패턴.검증
SourcePlatformFallbackTest12케이스 분기 망라. co.kr 2단 suffix, PSL private 섹션(myshopify.com), IP·단일 라벨·public suffix 는 원형 유지, PSL 미등재 호스팅 suffix(cafe24) 한계 고정. 예시 host 들은 Guava 번들 PSL 로 실측해 확정했다.Result
WishlistApi의 @ApiResponses 변화는 없고, 필드 문서화는 DTO @Schema 와WishlistApiExamples가 담당한다.연관 이슈
Summary by CodeRabbit
sourcePlatform필드 추가.