8.9 KiB
8.9 KiB
언어 감지·번역 공급자 공통화 PRD
| 항목 | 내용 |
|---|---|
| 작성일 | 2026-11-09 |
| 상태 | Phase 1·2 구현 및 기능 범위 검증·독립 리뷰 완료 |
| 승인 범위 | 감지·번역 별도 인터페이스, 공통 공급자 선택·실패 전환, 기능별 순서 설정 |
| 계획 | plan-task.md |
목적
파파고에 결합된 언어 감지·번역 호출을 분리한다. 이후 공급자는 해당 인터페이스 구현체와 빈·인증·순서 설정을 추가하면 사용할 수 있어야 하며, 콘텐츠·댓글·커뮤니티 등 도메인 코드에 공급자 분기를 추가하지 않는다.
범위와 제외
- 현재 실행되는 실제 구현체는 파파고뿐이다. AWS 실제 API·SDK 구현은 다음 작업이며 이번에는 추가하지 않는다.
- AWS 구현체가 등록된 뒤 기본 운영 의도는 파파고 → AWS이다. 감지와 번역 순서는 각각 독립 설정으로 바꾼다.
- 기본 실행 설정은 존재하는 파파고만 사용한다. 미구현 AWS를 등록한 것처럼 처리하거나 네트워크 호출하지 않는다.
- 기존 파파고 5,000 UTF-16 단위 분할, 지원 번역 언어 ko/en/ja, 공개 API, DB 스키마, job 재시도 정책은 유지한다.
- 감지 결과 저장 대상별 차이, 커뮤니티 원문 revision 검증, 이벤트 after-commit 처리 및 DB 경합 규칙을 유지한다.
- 실행 중 설정 변경, 관리 화면, 임의 플러그인 로딩, 새 번역 품질 정책, 기존 FAILED 작업 재처리는 제외한다.
요구사항
| ID | 수용 기준 |
|---|---|
| LP-001 | 감지와 번역은 독립된 공급자 인터페이스이며, 둘 중 하나만 구현한 공급자도 해당 기능에 등록 가능하다. |
| LP-002 | 감지·번역의 공급자 순서를 서로 다른 설정으로 지정한다. 테스트 공급자 2개로 한쪽만 순서를 바꿔도 다른 쪽에 영향이 없음을 증명한다. |
| LP-003 | 공급자별 예외 또는 유효 결과 없음이면 다음 공급자를 순서대로 한 번 시도한다. 첫 성공 뒤 후속 공급자를 호출하지 않는다. |
| LP-004 | 모든 공급자 실패 시 감지는 기존처럼 결과 없음으로 처리하고 번역은 기존 워커 실패·재시도 경로를 따른다. |
| LP-005 | 캐시는 실제 성공 공급자 이름으로 저장한다. AWS 역할의 가짜 공급자 성공을 papago 이름으로 저장하지 않는다. |
| LP-006 | 설정된 공급자들의 유효 캐시를 우선 재사용한다. 새 외부 호출의 순서는 별도 설정 순서를 따른다. 워커와 결과 조립의 캐시 선택 정책이 같다. |
| LP-007 | 빈 원문·동일 언어·서비스 미지원 번역 언어는 불필요한 공급자 전환을 일으키지 않는다. 유효한 미지원 언어 감지 결과는 감지 장애와 구분한다. |
| LP-008 | 빈/중복/알 수 없는 공급자 순서 설정은 초기화 단계에서 명확히 거부한다. 새 구현체 추가 시 기존 선택 코드나 공급자 enum 수정이 필요 없다. |
| LP-009 | 기존 파파고 캐시·번역 데이터 및 분할 번역 동작과 감지 캐시 동시성 승자 반환을 보존한다. |
| LP-010 | 추가 방법과 기능별 순서 설정 예시, 실제 AWS 미구현 상태를 문서화한다. |
| LP-011 | 공급자 순서는 LanguageProviderOrder의 독립 val List<String> 두 개로 지정한다. 기본은 각각 listOf("papago")이다. |
| LP-012 | 우선순위 환경변수·YAML·문자열 파싱을 제거한다. 기존 우선순위 property/env 값이 있어도 production 순서를 바꾸지 않는다. 인증정보 환경변수는 유지한다. |
보안·오류 처리
외부 HTTP 응답과 실행 설정이 신뢰 경계다. 부분 번역·빈 응답은 정상 결과로 저장하지 않는다. 원문, 인증정보, 공급자 응답 본문이 신규 로그나 워커 오류 문자열에 노출되지 않도록 한다. 공급자 식별자·순서 외에 임의 URL을 사용자 요청으로 받지 않는다. 유료 API 테스트는 하지 않는다.
검증 시나리오
- 파파고 단독 기본 설정에서 기존 감지·번역·캐시·분할·커뮤니티 동작이 유지된다.
- 두 가짜 공급자로 감지/번역 순서 독립 변경, 첫 성공 중단, 실패 전환·전체 실패를 확인한다.
- 가짜 보조 공급자의 감지/번역 결과가 실제 provider로 DB에 저장되고 다음 요청과 materializer가 재사용한다.
- 잘못된 설정의 초기화 실패, 원문 정책 가드, 캐시 동시성·revision 회귀를 검증한다.
검증 범위
변경 전 관련 focused 테스트 60건과 추가 end-to-end 4건 통과를 확인했다.
구현 후 새 계약 테스트를 포함한 85건 및 부모 런타임·HTTP 검증을 통과했다. 상세 증거는 계획 문서에 기록한다.
전체 테스트는 저장소 정책에 따라 사용자 실행(./gradlew test)이며, 운영 DDL·실제 AWS/Papago 계정 호출은 제외한다.
LSP 도구가 제공되지 않으면 Kotlin 컴파일과 ktlint로 보완하고 그 한계를 기록한다.
확정 구현 계약
아래는 Phase 1 구현 계약이며, 순서 설정 방식은 하단의 Phase 2 정정 계약이 우선한다. 기존 실행 기록은 보존한다.
- 기존
TranslationProvider와 rawTranslateResult는 유지한다. LanguageDetectionProvider:providerName: String,detect(query: String): String?.DetectedLanguage:detectedLanguage: String,providerName: String.ProviderTranslationResult:result: TranslateResult,providerName: String,providerVersion: String.- 기존
LanguageDetectionCacheService.detectWithCache(query: String): DetectedLanguage?가 감지 선택·캐시·전환을 담당한다. 기존 callback overload는 남기지 않고 모든 테스트 fixture도 새 계약에 맞춘다. TranslationCoordinator.findCached(sourceHash, sourceLanguage, targetLanguage): TranslationMemory?를 worker와 materializer가 함께 사용한다. 캐시 선택만 통일하며 DB 저장 트랜잭션은 기존 worker에 남긴다.TranslationCoordinator.translate(request: TranslateRequest): ProviderTranslationResult가 실제 성공 공급자를 반환한다. 결과 개수 불일치·blank 결과·공급자 예외는 다음 공급자로 전환한다. 부분 결과는 섞지 않고 전체 요청을 넘긴다.- 새 번역 coordinator의 빈 입력/blank 텍스트/동일 언어/미지원 언어 요청은 고정 메시지의
IllegalArgumentException으로 외부 호출 전에 거부한다. 기존 Papago raw adapter 가드는 그대로 유지한다. - 전체 번역 공급자 실패는 원문·원시 예외를 포함하지 않는
IllegalStateException("all translation providers failed")이다. 감지 전체 실패는 null이다. catch는 adapter 호출에만 적용하고 DB 실패를 공급자 실패로 처리하지 않는다. sodalive.language-providers.detection-order와translation-order는 각각 기본papago이다. 순서는 재시작/재배포 시 반영한다. 미등록 공급자는 설정 오류로 거부하며 AWS 구현 전에는aws를 활성화하지 않는다.- 감지 캐시의 정규화/hash 규칙과
insertIfAbsent다음findDetectedLanguageForUpdate승자 반환을 유지한다. adapter에는 기존처럼 원래 query를 전달한다. 유효한 ko/en/ja 밖 감지 결과는 공급자 실패로 재해석하지 않는다. - 공통
TranslationLanguages로 서비스 언어 정책만 옮긴다. Papago 분할은 Papago adapter에 유지한다. - 현재 entity에는 공급자별 cache key가 있으므로 DDL 변경 없이 실제 공급자를 기록한다. 캐시 두 개가 있으면 설정상 앞선 결과를 선택하며 특정 job의 공급자를 영구 고정하는 새 모델은 만들지 않는다.
Phase 2 결정 정정 — 2026-11-09
사용자는 YAML·환경변수 대신 코드의 상수 목록으로 감지·번역 순서를 지정하도록 승인했다.
- 유일한 production 순서 편집 지점은
i18n/translation/LanguageProviderOrder.kt의detectionOrder = listOf("papago"),translationOrder = listOf("papago")이다. Kotlin 목록은const val이 아닌val이다. - 목록의 왼쪽부터 사용한다. 감지·번역은 각각 수정할 수 있으며 변경 후 빌드·배포한다.
- 기존
LanguageProviderProperties는 typed-list 생성자와 명시적 Spring 기본 생성자로 코드 목록을 읽는다. 선택 코드·호출자의 이름 변경을 확산시키지 않는다. 문자열 생성자·@Value·split/trim은 제거한다. - 테스트는 전역 목록을 바꾸지 않고 테스트 전용 bean에 typed list를 주입하여 독립 순서와 invalid order를 검증한다.
- 과거 우선순위 environment/property override는 무시한다. 다른 환경변수나 Spring 설정 체계는 변경하지 않는다.
- 실패 전환·공급자 검증·캐시·DB·인증·AWS 미구현 정책은 Phase 1을 그대로 유지한다.