Skip to content

wish 응답에 출처 커머스몰 표시명(sourcePlatform) 추가#767

Merged
m-a-king merged 10 commits into
devfrom
feat/766-wish-source-platform
Jul 20, 2026
Merged

wish 응답에 출처 커머스몰 표시명(sourcePlatform) 추가#767
m-a-king merged 10 commits into
devfrom
feat/766-wish-source-platform

Conversation

@m-a-king

@m-a-king m-a-king commented Jul 19, 2026

Copy link
Copy Markdown
Collaborator

Situation

  • 위시에 담긴 상품이 어느 커머스몰에서 온 것인지 클라이언트에 내려줄 정보가 없다. item 은 원본 URL(source_url)만 들고 있어 클라가 host 를 직접 파싱해야 한다.
  • 몰 표기(브랜드 표기·한글명)는 운영 중 수시로 다듬어질 수 있어, 배포 없이 백오피스에서 수동 관리할 수 있어야 한다는 요구가 함께 있었다.

Task

  • wish 조회 응답에 출처 몰 표시명 필드를 추가하되, 백오피스 등록값을 우선하고 미등록 도메인도 임시값이나마 항상 보여주는 구조를 만든다.
  • 결정 포인트: 용어, 값을 컬럼에 저장할지 조회 시 유도할지, 미등록 도메인의 임시값을 얼마나 정교하게 뽑을지.

Action

설계 결정

저장 방식:

선택지 장점 단점 결정
items 컬럼 저장 몰별 SQL 집계가 값싸고 정확 (인덱스·GROUP BY) 기존 행 백필 필요, 등록을 더할 때마다 재백필, 표기 수정이 과거 행에 안 퍼짐 기각
조회 시 유도 백오피스 수정·신규 등록이 과거 item 에 즉시 소급, 마이그레이션·백필 불필요 SQL 집계는 source_url LIKE·host 추출로 우회해야 함 (풀스캔, 매핑 규칙을 SQL 로 재표현, PSL fallback 은 SQL 재현 불가라 몰 롤업은 앱 몫) 채택

미등록 도메인의 임시 표시명(fallback) 규칙:

선택지 예시 거동 결정
www. 만 뗀 host 원형 shop.29cm.co.kr 이 그대로 나감 기각 (요구는 "정확히 29cm")
왼쪽 라벨 global.oliveyoung.com 이 "global" 로 나감 기각 (기능성 서브도메인에서 자주 틀림)
PSL 기반 등록 가능 도메인의 첫 라벨 shop.29cm.co.kr 은 "29cm", brand.myshopify.com 은 "brand" (PSL private 섹션의 커머스 호스팅 suffix) 채택
  • 용어: 응답 필드 sourcePlatform, 테이블 source_platforms. item 의 기존 컬럼(source_url·source_image_key)과 source_ 접두가 정렬되고, 추출 쪽 기존 어휘(extraction_platform_policies)와 platform 이 일치한다.
  • 값 의미: 안정 code 계약이 아니라 서버 소유 표시명 문자열이다. fallback 이 URL 유래 문자열인 이상 닫힌 code 집합이 될 수 없고, 표기 수정이 배포 없이 끝나는 것이 수동 관리 요구와 정합이다. 클라이언트는 opaque 표시 텍스트로만 취급한다.
  • PSL 의 한계도 합의하고 고정: PSL 에 없는 호스팅 suffix 는 입점 브랜드가 아니라 호스팅사 라벨로 떨어진다 (실측: brand.cafe24.com 은 "cafe24", cafe24.com 이 PSL 미등재). host 문자열만으로 어느 라벨이 브랜드인지 판별할 수 없는 케이스라, 이런 잔여는 백오피스 수동 등록이 덮기로 했다. 이 거동을 단위 테스트로 고정했다.

구현

  • 응답: WishItemResponse.ItemView·WishPriceHistoryResponse 에 sourcePlatform(nullable) 추가. 리졸버는 빈이라 컨트롤러가 판정을 풀어 DTO 의 from 에 넘긴다.
  • 레지스트리: source_platforms(domain PK, display_name) 테이블 + DbSourcePlatformResolver. @volatile 불변 리스트 캐시, 도메인 길이 내림차순 최장 일치, afterCommit·5분 주기 reload. DbExtractionRoutingPolicy 패턴 재사용.
  • fallback: SourcePlatformFallback 이 Guava InternetDomainName.topPrivateDomain() 의 첫 라벨을 뽑는다. 도메인 문법이 아니면(IP 등) host 원형, 이미지 등록 item(URL 없음)은 null.
  • host 정규형(소문자·trailing dot 제거)은 ProductLink.normalizedHost() 로 승격해 matchesAnyDomain 과 공유한다.
  • 백오피스: /admin/source-platforms 목록(추가 폼)·상세(수정·삭제). 도메인 정규화·길이 검증, SOURCE_PLATFORM_UPDATE 감사 기록, 어드민 홈 카드 추가. AdminExtractionPolicyController 패턴.
  • 의존성: Guava 를 명시 선언으로 승격(33.6.0-jre, Maven Central 최신 안정). firebase-admin 전이에 기대면 제공자가 Guava 를 떨굴 때 조용히 깨진다.

검증

  • 단위: SourcePlatformFallbackTest 12케이스 분기 망라. co.kr 2단 suffix, PSL private 섹션(myshopify.com), IP·단일 라벨·public suffix 는 원형 유지, PSL 미등재 호스팅 suffix(cafe24) 한계 고정. 예시 host 들은 Guava 번들 PSL 로 실측해 확정했다.
  • 통합: 백오피스 CRUD 가 정규화 저장, afterCommit 즉시 반영(서브도메인 포함 매칭), 삭제 시 fallback 복귀를 리졸버 실체로 단언. 기존 wish 등록·가격 히스토리·이미지 등록 테스트에 sourcePlatform contract 단언 추가(미등록 도메인 fallback, 이미지 등록은 null).

Result

  • 시드 없음: 등록 전까지 모든 도메인이 fallback 표시명(소문자, 예: 29cm·musinsa)으로 나간다. 정식 브랜드 표기(29CM·무신사 등)는 운영자가 백오피스에서 등록하는 순간 과거 위시에도 즉시 적용된다.
  • blue-green 공존·수평 확장에서 표시명 변경 전파는 다른 인스턴스 기준 최대 5분(주기 reload) 지연될 수 있다. 추출 라우팅 정책과 같은 특성이다.
  • 새 status 코드가 없어 WishlistApi 의 @ApiResponses 변화는 없고, 필드 문서화는 DTO @SchemaWishlistApiExamples 가 담당한다.

연관 이슈

Summary by CodeRabbit

  • 새로운 기능
    • 관리자에서 도메인별 출처 플랫폼 표시명(목록·상세·추가/수정/삭제) 관리 화면 제공.
    • 위시리스트 및 가격 히스토리 응답에 sourcePlatform 필드 추가.
  • 개선
    • 미등록 도메인은 PSL 기반 임시 표시명으로 자동 노출.
    • 도메인 입력 정규화 및 잘못된 입력/조회 시 화면 전환·안내 동작 보강.
  • 테스트
    • 관리자 플로우, fallback 규칙, API 응답 동작 통합 검증 테스트 추가.

m-a-king added 2 commits July 19, 2026 16:21
- 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 과 공유
@m-a-king m-a-king added the feat 외부 가시적 새 기능 label Jul 19, 2026
@m-a-king m-a-king linked an issue Jul 19, 2026 that may be closed by this pull request
@m-a-king m-a-king self-assigned this Jul 19, 2026
@github-actions

Copy link
Copy Markdown

Discord 스레드 연동용 메타데이터입니다. discord-pr-bot 워크플로가 자동 생성하며, 수정·삭제하면 PR 과 Discord 알림 연동이 끊깁니다.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro Plus

Run ID: 661bdd63-2bea-4490-974a-74e59c479033

📥 Commits

Reviewing files that changed from the base of the PR and between 1fd9ad6 and 4a479d0.

📒 Files selected for processing (3)
  • CLAUDE.md
  • src/main/resources/templates/admin/index.html
  • src/main/resources/templates/admin/source-platforms.html
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/resources/templates/admin/index.html
  • src/main/resources/templates/admin/source-platforms.html

Walkthrough

도메인별 출처 플랫폼 표시명 레지스트리와 관리자 CRUD를 추가하고, 메모리 캐시 및 PSL fallback으로 표시명을 결정한다. 결정된 값은 위시 항목과 가격 이력 응답의 sourcePlatform에 포함된다.

Changes

출처 플랫폼 표시명 기능

Layer / File(s) Summary
플랫폼 저장 및 도메인 해석
build.gradle.kts, src/main/kotlin/com/depromeet/piki/product/{domain,source}/*, src/main/resources/db/migration/*, src/test/kotlin/com/depromeet/piki/product/source/*
source_platforms 저장 구조, 도메인 정규화, PSL fallback, 최장 도메인 매칭 캐시와 재적재 로직을 추가했다.
관리자 CRUD와 캐시 갱신
src/main/kotlin/com/depromeet/piki/admin/*, src/main/resources/templates/admin/*, src/test/kotlin/com/depromeet/piki/admin/sourceplatform/*
관리자 목록·상세·등록·수정·삭제 화면과 라우팅을 추가하고, 입력 검증·감사 기록·커밋 후 resolver 갱신을 연결했다.
위시 응답 필드 연결
src/main/kotlin/com/depromeet/piki/wishlist/controller/*, src/main/kotlin/com/depromeet/piki/wishlist/controller/dto/*, src/test/kotlin/com/depromeet/piki/wishlist/controller/*
WishItemResponseWishPriceHistoryResponse에 nullable sourcePlatform을 추가하고, 위시 응답 생성 시 resolver 결과를 주입했다. API 예시와 통합 검증도 갱신했다.

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 포함 응답
Loading

Assessment against linked issues

Objective Addressed Explanation
[직접 연결 #766] 위시 항목·가격 이력 응답에 nullable sourcePlatform 추가
[직접 연결 #766] 도메인 레지스트리, 관리자 CRUD, 최장 일치 캐시 추가
[직접 연결 #766] PSL fallback 및 IP·이미지 등록 예외 처리
[직접 연결 #766] Guava를 명시 의존성으로 추가하고 저장 없이 조회 시 유도
🚥 Pre-merge checks | ✅ 1 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/766-wish-source-platform

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

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

📥 Commits

Reviewing files that changed from the base of the PR and between 02743c5 and 439b034.

📒 Files selected for processing (22)
  • build.gradle.kts
  • src/main/kotlin/com/depromeet/piki/admin/audit/AdminAuditAction.kt
  • src/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformController.kt
  • src/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformService.kt
  • src/main/kotlin/com/depromeet/piki/product/domain/ProductLink.kt
  • src/main/kotlin/com/depromeet/piki/product/source/SourcePlatformEntity.kt
  • src/main/kotlin/com/depromeet/piki/product/source/SourcePlatformFallback.kt
  • src/main/kotlin/com/depromeet/piki/product/source/SourcePlatformJpaRepository.kt
  • src/main/kotlin/com/depromeet/piki/product/source/SourcePlatformResolver.kt
  • src/main/kotlin/com/depromeet/piki/wishlist/controller/WishlistApiExamples.kt
  • src/main/kotlin/com/depromeet/piki/wishlist/controller/WishlistController.kt
  • src/main/kotlin/com/depromeet/piki/wishlist/controller/dto/WishItemResponse.kt
  • src/main/kotlin/com/depromeet/piki/wishlist/controller/dto/WishPriceHistoryResponse.kt
  • src/main/resources/db/migration/V20260719160822__create_source_platforms.sql
  • src/main/resources/templates/admin/index.html
  • src/main/resources/templates/admin/source-platform-detail.html
  • src/main/resources/templates/admin/source-platforms.html
  • src/test/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformIntegrationTest.kt
  • src/test/kotlin/com/depromeet/piki/product/source/SourcePlatformFallbackTest.kt
  • src/test/kotlin/com/depromeet/piki/wishlist/controller/WishPriceHistoryIntegrationTest.kt
  • src/test/kotlin/com/depromeet/piki/wishlist/controller/WishlistImagePresignedIntegrationTest.kt
  • src/test/kotlin/com/depromeet/piki/wishlist/controller/WishlistRegisterAsyncIntegrationTest.kt

@github-actions
github-actions Bot requested a review from sevineleven July 19, 2026 07:30
m-a-king added 3 commits July 19, 2026 18:41
- 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 지적 수용 - 기존 테스트는 단일 등록 도메인만 검증했다)

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

📥 Commits

Reviewing files that changed from the base of the PR and between c496c0d and 1169d10.

📒 Files selected for processing (2)
  • src/main/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformService.kt
  • src/test/kotlin/com/depromeet/piki/admin/sourceplatform/AdminSourcePlatformIntegrationTest.kt

m-a-king and others added 2 commits July 20, 2026 06:29
- raw 키 findById 만으로는 입력이 정규화된 다른 키로 저장되는 경우를 못 잡는다 (CodeRabbit 지적 수용) - 요청 전후 count 비교로 "어떤 키로도 저장 없음"을 고정
@m-a-king

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review body 의 outside-diff 지적(AdminSourcePlatformService.kt 53-58, "무결성 예외를 모두 중복 저장으로 변환하지 마세요")에 대한 판정: Rejected.

  • 이 테이블(source_platforms)의 제약은 PK(domain) 하나뿐이다. display_name 의 NOT NULL 은 Kotlin 타입이, 길이는 저장 전 validateLengths 가 막아 정상 경로에서 다른 무결성 위반이 이 catch 에 닿을 수 없다.
  • JPA(Hibernate) 예외 번역은 duplicate key 를 DuplicateKeyException 으로 안정적으로 세분화해 주지 않고 DataIntegrityViolationException 으로 뭉갠다. "DB 확인된 duplicate 만" 판별하려면 cause 체인에서 벤더별 제약명을 파싱해야 해 오히려 더 깨지기 쉽다.
  • 같은 트레이드오프를 이미 겪은 기존 AdminExtractionPolicyService 와 동일 패턴(광의 catch + 주석으로 사유 명시)을 유지해 관리 화면 계열의 일관성을 지킨다.
  • 이후 이 테이블에 새 제약이 추가되는 마이그레이션 PR 이 생기면, 그 PR 이 이 catch 의 세분화를 함께 책임지는 것이 맞다.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@m-a-king 설명해 주신 현재 스키마 제약과 기존 AdminExtractionPolicyService의 일관성을 고려하면, 이 경우 광의의 DataIntegrityViolationException 처리는 의도된 트레이드오프로 타당합니다. 해당 지적은 철회하겠습니다.

향후 source_platforms에 PK 이외 제약이 추가되는 마이그레이션에서는, 말씀하신 대로 그 변경과 함께 예외 처리 범위를 재검토하면 됩니다. 🐰


✏️ Learnings added
Learnt from: m-a-king
URL: https://github.com/TeamPiKi/core/pull/767

Timestamp: 2026-07-19T21:34:19.034Z
Learning: `source_platforms` 테이블은 현재 `domain` PK만 무결성 제약으로 가지며, `AdminSourcePlatformService`는 Hibernate의 이식 가능한 duplicate-key 예외 세분화가 어렵다는 이유로 `DataIntegrityViolationException`을 중복 도메인 저장 오류로 처리한다. 이는 기존 `AdminExtractionPolicyService`와 동일한 관리 화면 계열 패턴이다. 향후 `source_platforms`에 추가 무결성 제약을 도입하는 마이그레이션은 이 catch 처리의 세분화를 함께 검토해야 한다.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

m-a-king and others added 3 commits July 20, 2026 20:32
- 표시명 칸(.n)에 min-width 0 + max-width 45% + ellipsis + title 툴팁 - maxlength 255 표시명이 도메인 칸을 0 폭까지 밀고 행을 가로로 넘치게 하던 구조를 도메인 칸과 같은 규칙으로 정렬 (코드리뷰 반영)
- 어드민 홈 lede 가 알림·공지만 언급해 카드 5개와 어긋나던 기존 드리프트를 이번 카드 추가에 맞춰 갱신
- 컨트롤러/OpenAPI 규약의 정당 예외 열거가 실제 코드와 어긋나면 컨벤션 점검이 미분류 위반으로 오인한다 (코드리뷰 반영)
@m-a-king
m-a-king merged commit cd604f1 into dev Jul 20, 2026
10 checks passed
@m-a-king
m-a-king deleted the feat/766-wish-source-platform branch July 20, 2026 13:09
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.

wish 응답에 출처 커머스몰 표시명(sourcePlatform) 추가

1 participant