From b956d8ae81a3c037003604c98a69ade54b759a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Sun, 12 Jul 2026 00:32:46 +0900 Subject: [PATCH] =?UTF-8?q?chore:=20=EC=98=9B=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=EB=AA=85=20=EC=82=B0=EB=AC=B8=20=ED=91=9C=EA=B8=B0?= =?UTF-8?q?=EB=A5=BC=20core=C2=B7renderer=20=EB=A1=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - org 이관·repo 소문자화(PIKI-Server→core, PIKI-Extractor→extractor, PIKI-HeadlessBrowser→renderer)에 맞춰 CLAUDE.md·README·docs/api-contract.md·build.gradle.kts·코드 주석·테스트 주석에 남아있던 옛 이름 표기를 새 이름으로 정리 - README 의 관련 repo 링크(https://github.com/depromeet/PIKI-Server)도 이관된 좌표(https://github.com/TeamPiKi/core)로 갱신 - telemetry 값이 있는 application.yml(main·test)은 다른 세션이 rename 작업 중인 핫존이라 스킵 - 이 repo 를 가리키는 단독 'Extractor' 표기(PIKI 접두 없음)는 이번 정리 대상이 아니라 그대로 둠 - 기능 변경 없음, 산문만 수정 --- .github/workflows/ci.yml | 2 +- CLAUDE.md | 20 +++++++------- README.md | 6 ++--- build.gradle.kts | 10 +++---- docs/api-contract.md | 26 +++++++++---------- .../extractor/api/ExtractionController.java | 2 +- .../extractor/api/ExtractionResponse.java | 2 +- .../common/exception/ExtractionErrorCode.java | 2 +- .../common/storage/ImageStorage.java | 2 +- .../common/storage/ImageStorageException.java | 2 +- .../common/storage/S3ImageStorage.java | 2 +- .../piki/extractor/domain/ProductLink.java | 2 +- .../extractor/domain/ProductSnapshot.java | 2 +- .../FallbackProductLinkExtractor.java | 2 +- .../HeadlessExtractionProperties.java | 4 +-- .../HeadlessProductLinkExtractor.java | 2 +- .../extraction/ProductLinkExtractor.java | 2 +- .../extraction/gemini/GeminiProperties.java | 2 +- .../extraction/headless/HeadlessRenderer.java | 2 +- .../headless/HttpHeadlessRenderer.java | 2 +- .../image/ImageExtractionService.java | 2 +- .../image/domain/ProductImageException.java | 2 +- .../api/ExtractionImageIntegrationTest.java | 2 +- .../api/ExtractionLinkIntegrationTest.java | 2 +- .../extractor/domain/ProductLinkTest.java | 2 +- .../FallbackProductLinkExtractorTest.java | 4 +-- .../extractor/support/TestConventionTest.java | 2 +- 27 files changed, 56 insertions(+), 56 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98f68b5..45a943d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -# PIKI-Server 의 ci.yml 과 같은 구조를 따르되, 이 서비스는 DB 가 없어 Testcontainers/Docker 없이 test 까지 그냥 돈다. +# core 의 ci.yml 과 같은 구조를 따르되, 이 서비스는 DB 가 없어 Testcontainers/Docker 없이 test 까지 그냥 돈다. name: CI on: diff --git a/CLAUDE.md b/CLAUDE.md index bc303d6..eb91bbe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,13 +1,13 @@ -# PIKI-Extractor 프로젝트 컨벤션 +# extractor 프로젝트 컨벤션 ## 이 서비스의 정체 -PIKI-Server(코틀린)에서 분리된 **상품 추출 서비스**다. 상품 URL(또는 S3 이미지)을 받아 fetch → 구조화 파싱(JSON-LD/OG) → LLM(Gemini) fallback → 정규화를 거쳐 추출 결과를 돌려준다. +core(코틀린)에서 분리된 **상품 추출 서비스**다. 상품 URL(또는 S3 이미지)을 받아 fetch → 구조화 파싱(JSON-LD/OG) → LLM(Gemini) fallback → 정규화를 거쳐 추출 결과를 돌려준다. -- **무상태.** DB 없음, 호출 간 상태 없음. 상태를 넣고 싶어지면 설계 경고 신호다. 재시도·내구성·상태 전이는 전부 호출자(PIKI-Server outbox)의 몫이다. -- **소비자는 PIKI-Server 워커 하나뿐.** 공개 API 가 아니다. 보안그룹 내부망 전용, 인증 없음. +- **무상태.** DB 없음, 호출 간 상태 없음. 상태를 넣고 싶어지면 설계 경고 신호다. 재시도·내구성·상태 전이는 전부 호출자(core outbox)의 몫이다. +- **소비자는 core 워커 하나뿐.** 공개 API 가 아니다. 보안그룹 내부망 전용, 인증 없음. - **계약의 single source 는 `docs/api-contract.md`.** 응답은 3갈래뿐이다: 2xx(성공) / 422+code(확정 실패) / 그 외 전부(일시 실패). 진화는 additive-only, 배포는 Extractor 먼저. -- 차단 우회 **방법론**(스텔스·프록시·IP 전략)은 private repo(PIKI-HeadlessBrowser)에만 둔다. 이 repo(public)에는 "이 호스트는 헤드리스로 라우팅" 수준까지만 담는다. +- 차단 우회 **방법론**(스텔스·프록시·IP 전략)은 private repo(renderer)에만 둔다. 이 repo(public)에는 "이 호스트는 헤드리스로 라우팅" 수준까지만 담는다. ## 언어: Java 25 @@ -16,7 +16,7 @@ PIKI-Server(코틀린)에서 분리된 **상품 추출 서비스**다. 상품 UR ### Null 처리 -PIKI-Server 의 Elvis 규칙에 대응하는 Java 규칙: +core 의 Elvis 규칙에 대응하는 Java 규칙: - 파라미터·필드의 non-null 강제는 `Objects.requireNonNull(x, "메시지")`. - "없을 수 있음"을 반환할 땐 `Optional` 또는 도메인 결과 타입(sealed). **null 반환 금지.** @@ -28,7 +28,7 @@ PIKI-Server 의 Elvis 규칙에 대응하는 Java 규칙: ## 예외 정책 -판단 기준 한 줄은 PIKI-Server 와 같다: **"정상 호출로 여기 닿을 수 있나?"** 단, 이 서비스의 클라이언트는 PIKI-Server 워커다. +판단 기준 한 줄은 core 와 같다: **"정상 호출로 여기 닿을 수 있나?"** 단, 이 서비스의 클라이언트는 core 워커다. - 닿는다 → **계약** → `ExtractionException`(커스텀, code + 일시/확정 구분 내장) → 핸들러가 422 또는 502 로 매핑. - 못 닿는다 → **불변식** → `IllegalStateException`/`IllegalArgumentException` → 일반 500. 호출자는 이를 "일시 실패"로 보고 bounded 재시도하므로 안전하다. @@ -45,12 +45,12 @@ PIKI-Server 의 Elvis 규칙에 대응하는 Java 규칙: ## 포팅 규율 (이관 기간 한정) - **동작 등가(파리티)가 목표다.** Kotlin 원본의 분기·상수·메시지를 그대로 옮기고, 개선·리팩터링은 이관 완료 후 별도 작업으로 뺀다. -- 포팅한 클래스 상단 주석에 원본 경로를 남긴다: `// PIKI-Server: product/service/http/HttpPageFetcher.kt 포팅`. +- 포팅한 클래스 상단 주석에 원본 경로를 남긴다: `// core: product/service/http/HttpPageFetcher.kt 포팅`. - 하드코딩이던 상수(fetch 3MB cap·UA·타임아웃·LLM 200K char cap)는 `@ConfigurationProperties` 로 외부화하되 **기본값은 원본과 동일**하게 둔다. ## 테스트 -PIKI-Server 테스트 컨벤션의 Java 번역판. 원문 규약이 더 자세하다 (PIKI-Server `.claude/rules/testing-convention.md`). +core 테스트 컨벤션의 Java 번역판. 원문 규약이 더 자세하다 (core `.claude/rules/testing-convention.md`). - **분류**: 단위(Spring 없이 분기 망라) / 통합(HTTP 진입 계약 검증, 외부는 stub) / E2E(실제 몰·Gemini 호출, env 격리). **DB 가 없으므로 Testcontainers·Docker 불필요** — `./gradlew test` 가 그냥 돈다. - **모킹 금지, stub 우선.** Mockito/`@MockBean` 금지. 외부 경계(GeminiClient·PageFetcher·S3)는 `IntegrationStubs` 한 곳에 `@Primary` stub 빈으로 등록, default 람다는 throw. @@ -64,7 +64,7 @@ PIKI-Server 테스트 컨벤션의 Java 번역판. 원문 규약이 더 자세 - 버전의 single source 는 `build.gradle.kts`. 문서에 버전 숫자를 박지 않는다. - 새 의존성은 Maven Central 최신 안정 버전(pre-release 제외), Spring Boot BOM 관리 대상은 버전 명시 금지. -- PIKI-Server 와 공유하는 라인(jsoup·guava·AWS SDK·springdoc)은 그쪽과 버전을 맞춘다. +- core 와 공유하는 라인(jsoup·guava·AWS SDK·springdoc)은 그쪽과 버전을 맞춘다. ## 브랜치·PR diff --git a/README.md b/README.md index b95f6f5..f75dadd 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# PIKI-Extractor +# extractor -PIKI 의 상품 추출 서비스. 상품 URL(또는 S3 이미지)을 받아 fetch → 구조화 파싱(JSON-LD/OpenGraph) → LLM(Gemini) fallback → 정규화를 거쳐 추출 결과를 반환한다. PIKI-Server 의 파싱 파이프라인을 분리한 것으로, 소비자는 PIKI-Server 의 outbox 워커 하나뿐인 내부 서비스다. +PIKI 의 상품 추출 서비스. 상품 URL(또는 S3 이미지)을 받아 fetch → 구조화 파싱(JSON-LD/OpenGraph) → LLM(Gemini) fallback → 정규화를 거쳐 추출 결과를 반환한다. core 의 파싱 파이프라인을 분리한 것으로, 소비자는 core 의 outbox 워커 하나뿐인 내부 서비스다. - **API 계약**: [docs/api-contract.md](docs/api-contract.md) — 응답 3갈래(2xx / 422 / 그 외=재시도), additive-only 진화 - **스택**: Java 25 · Spring Boot 4 · virtual threads · 무상태(DB 없음) -- **관련 repo**: [PIKI-Server](https://github.com/depromeet/PIKI-Server) (호출자), PIKI-HeadlessBrowser (차단 우회 렌더링, private) +- **관련 repo**: [core](https://github.com/TeamPiKi/core) (호출자), renderer (차단 우회 렌더링, private) ## 실행 diff --git a/build.gradle.kts b/build.gradle.kts index c0ca2e3..9b6e1e0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,7 +17,7 @@ repositories { mavenCentral() } -// 이미지(OCR) 경로의 S3 raw 읽기·크롭 업로드용. 버전 라인은 PIKI-Server 와 동일하게 유지한다. +// 이미지(OCR) 경로의 S3 raw 읽기·크롭 업로드용. 버전 라인은 core 와 동일하게 유지한다. val awsSdkVersion = "2.44.11" dependencyManagement { @@ -31,15 +31,15 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-validation") // OpenAPI 문서 노출(/v3/api-docs, UI 없음). 계약의 원문은 docs/api-contract.md. - // Spring Boot 4 / Jackson 3 호환 라인 — PIKI-Server 와 동일. + // Spring Boot 4 / Jackson 3 호환 라인 — core 와 동일. implementation("org.springdoc:springdoc-openapi-starter-webmvc-api:3.0.3") // 상품 페이지 HTML 에서 구조화 데이터(JSON-LD