Files

8.2 KiB

v2 콘텐츠 목록 요청 언어별 번역 PRD

문서 정보

  • 작성일: 2026-09-09
  • 상태: Phase 1·2 구현 및 자동 검증 완료, test 서버 HTTP Gate 대기
  • 결정권자: 사용자
  • 관련 계획: plan-task.md
  • 공개 API 경로·요청·응답 스키마는 유지하며 별도 API 계약 문서는 만들지 않는다.
  • 사용자의 2026-09-09 구현 지시 이후 Phase 1·2 코드·테스트 구현을 진행했다. 운영 데이터 변경과 번역 실행은 수행하지 않는다.

1. 문제와 목표

동일한 콘텐츠라도 v2 조회 위치에 따라 번역 제목과 원문이 혼재한다. 요청의 Accept-Language로 결정된 언어에 맞춰 이미 저장된 번역을 표시하고, 번역이 없거나 공백이면 해당 필드의 기존 원문을 표시한다.

서버의 언어 결정은 기존 LangInterceptor → 요청 범위 LangContext를 재사용한다. 앱의 설정 언어가 실제 헤더로 전송되는지는 이 서버 작업에서 보장하지 않는다.

2. 대상 API와 필드

아래 경로는 모두 GET이다. 기존 응답에 존재하는 필드만 변경하며 설명·태그 같은 새 필드를 추가하지 않는다.

ID API 대상
LIST-01 /api/v2/creator-channels/{creatorId}/audio 오디오 title, 연결된 seriesName, 테마명
LIST-02 /api/v2/creator-channels/{creatorId}/series 시리즈 title. 기존 연재 요일 언어 처리 유지
LIST-03 /api/v2/audio/contents 오디오 title, 시리즈 title. 기존 type·정렬·요일 필터 유지
LIST-04 /api/v2/creator-channels/{creatorId}/home 오디오 카드 title·seriesName, 시리즈 title, 일정 중 AUDIO 유형의 title
LIST-05 /api/v2/audio/recommendations latestAudios, newAndHotAudios, freeAudios, pointAudios, mostCommentedAudios, recommendedAudios의 title
LIST-06 /api/v2/audio/rankings 각 랭킹 항목 title
LIST-07 /api/v2/contents NEW_AND_HOT_AUDIO, FIRST_AUDIO_CONTENT의 title
  • LIST-05의 originalSeries는 현재 seriesId·coverImageUrl만 반환한다. 번역용 title 필드를 추가하지 않는다.
  • LIST-04의 라이브 제목, 후원·팬톡 문구 등 오디오·시리즈·테마 외 필드는 대상이 아니다.
  • /api/v2/home/recommendations 등 다른 경로는 신규 기능 범위가 아니다. 공유 조회 코드 변경 시 기존 동작 회귀를 검증한다.
  • 관리자 목록, 상세·검색 API, 음성 파일 번역, 설명·태그 응답 확장은 제외한다.

3. 기능 요구사항과 수용 기준

ID 상태/근거 요구사항 수용 기준 연결
LANG-01 사용자 확정 대상 API 전체에서 Accept-Language 기준 번역 선택 동일 데이터에 ko/en/ja 요청 시 해당 locale 번역 표시 모든 Task
LANG-02 기존 동작 유지 Lang.fromAcceptLanguage 파싱 재사용 헤더 누락·빈 값·미지원 값은 ko, en-US는 en, ja-JP는 ja. q 가중치 파싱 확장 없음 P1-GATE
TEXT-01 사용자 확정 번역 없음·빈 문자열·공백 문자열은 원문 표시 null/빈 문자열/공백별 원문 일치, 다른 언어 번역으로 대체하지 않음 모든 Task
TEXT-02 사용자 확정 오디오 제목·시리즈 제목/시리즈명·테마명만 적용 댓글·닉네임·배너는 기존 값·선택 정책 유지 모든 Task
COMPAT-01 기존 기능 유지 언어는 표시 문자열에만 영향 ID·개수·순서·hasNext·권한·성인/차단/구매 필터·가격·이미지 불변 각 Gate
RANK-01 구현 제약 랭킹 집계와 번역 표시를 분리 같은 스냅샷으로 언어만 바꿔 제목 변경, 순위·점수·rankChange 불변 P2-T2
READ-01 범위 제약 저장된 번역만 조회 GET에서 Papago 호출·번역 작업 생성·DB 쓰기 없음 각 Gate
ISOLATE-01 기존 요청 범위 유지 언어가 다른 요청끼리 값 공유 금지 en→ja→en 요청에서도 언어 혼입 없음 각 Gate

원문이란 번역 적용 전 해당 경로에서 반환하던 문자열이다. 랭킹은 기존 스냅샷 title을 fallback으로 유지하며 최신 콘텐츠 제목으로 갱신하는 별도 기능을 추가하지 않는다. 번역 완료 전 원문이 보이는 것은 정상이다. 원문과 요청 언어가 같아도 별도 추정 없이 같은 locale 번역 조회/fallback 규칙을 적용한다.

4. 기술 근거와 최소 변경 방향

모든 경로는 src/main/kotlin/kr/co/vividnext/sodalive/ 아래를 기준으로 한다.

근거 파일 현재 확인한 동작
i18n/LangInterceptor.kt, i18n/Lang.kt, configs/WebConfig.kt 전체 경로에서 헤더를 읽고 ko/en/ja로 결정
content/translation/ContentTranslationRepository.kt findByContentIdInAndLocale 일괄 조회가 이미 존재
i18n/translation/TranslationReadModelMaterializer.kt content·series 번역을 renderedPayload에 저장
v2/creator/channel/audio/adapter/out/persistence/DefaultCreatorChannelAudioQueryRepository.kt 오디오 title·seriesName·테마는 요청 locale 번역 우선
v2/creator/channel/series/adapter/out/persistence/DefaultCreatorChannelSeriesQueryRepository.kt 시리즈 번역 우선과 원문 fallback 구현됨
v2/creator/channel/home/adapter/out/persistence/DefaultCreatorChannelHomeQueryRepository.kt 오디오·시리즈 제목 및 AUDIO 일정 제목은 요청 locale 번역 우선
v2/content/all/adapter/out/persistence/DefaultMainContentAllQueryRepository.kt 오디오·시리즈 제목은 요청 locale 번역 우선
v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt 일반 카드 및 mostCommentedAudios 제목은 요청 locale 번역 우선
v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt FIRST_AUDIO_CONTENT 제목은 요청 locale 번역 우선
v2/content/ranking/application/AudioRankingQueryService.kt 요청 locale을 조회 port에 전달하고 snapshot 표시 제목만 번역

기존 QueryService → Port → Persistence 경계를 유지하며 필요한 locale을 전달한다. 기존 번역 조인 또는 ID 일괄 조회를 재사용한다. 항목별 단건 조회로 N+1을 만들지 않는다. 페이지·정렬·필터 결과를 유지한 채 제목을 매핑한다. 별도 범용 번역 프레임워크·캐시·의존성·DDL은 추가하지 않는다. 랭킹/추천 스냅샷 생성 작업에 요청 범위 LangContext를 주입하지 않는다.

5. 검증 시나리오

  1. 같은 원문에 ko/en/ja별 서로 다른 번역을 준비하고 7개 API의 대상 필드가 헤더에 맞는지 확인한다.
  2. 번역 행 없음, 빈 제목, 공백 제목, 다른 locale 번역만 존재하는 경우 필드별 원문 fallback을 확인한다.
  3. 오디오 번역만 있고 시리즈 번역이 없는 혼합 사례에서 각 필드가 독립적으로 선택되는지 확인한다.
  4. 언어를 바꿔도 콘텐츠 ID·순서·페이지·필터·랭킹과 제외 필드가 동일한지 확인한다.
  5. 실제 HTTP 요청과 DB 조회 테스트로 연결을 검증한다. Mock 응답의 문자열 확인만으로 완료 처리하지 않는다.

6. 결정 기록

날짜 ID 구분 내용
2026-09-09 DEC-LIST-01 사용자 확정 앞서 조사한 조회 위치 모두 Accept-Language에 따른 번역 표시
2026-09-09 DEC-LIST-02 사용자 확정 번역 없음·공백이면 원문 표시
2026-09-09 DEC-LIST-03 사용자 확정 오디오 제목·시리즈 제목/시리즈명·테마명 대상, 댓글·닉네임·배너 유지
2026-09-09 DEC-LIST-04 기존 동작 유지 언어 파싱·기본 언어·인증·조회 조건·응답 스키마 유지
2026-09-09 DEC-LIST-05 사용자 제한 문서만 작성, 구현하지 않음
2026-09-09 DEC-LIST-06 사용자 지시 현재 브랜치에서 Phase 1 구현 진행. PRD에도 구현 상태를 최종 갱신
2026-09-09 DEC-LIST-07 사용자 지시 로컬 수동 테스트가 불가능하므로 Phase 2까지 자동 검증을 완료하고 test 서버에서 HTTP 검증

제품 결정이 필요한 미결 항목은 없다. test 서버 배포 후 대상 7개 API의 수동 HTTP 검증이 남아 있다.