docs(banner): 언어 필터 계약과 검증 결과를 기록한다
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
|
||||
**상태:** 소프트 삭제와 두 추천 API 통합의 백엔드 구현·검증 완료, 미배포. 전체 테스트·lint·빌드와 독립 리뷰를 통과했다. 제공 환경을 확인하기 전 운영 연동 또는 서버 배포가 완료됐다고 가정하지 않는다.
|
||||
|
||||
2026-11-03 국가별 언어 후속 계약의 전체 2,928개 테스트·영향 HTTP 재검증·lint·빌드·독립 리뷰를 완료했다. 서버 배포 전 신규 환경은 `create-sub-banner.sql`, 기존 테이블은 `20261102_add_sub_banner_lang.sql`로 `lang` 컬럼을 준비해야 한다. 운영 적용은 미실행이며 앱 작업에서 migration이나 운영 DB 변경을 실행하지 않는다.
|
||||
|
||||
## 목표
|
||||
|
||||
메인 홈 추천과 메인 콘텐츠 추천 화면에 가로형 서브 배너 영역을 추가한다. 각 placement 목록에 여러 배너가 있을 수 있다. 아래 API와 데이터 계약은 구현된 계약이다. 화면 배치, 표현, 링크 우선순위, fetch 실패 시 UI 처리는 작성자 추천이며 기존 앱 패턴을 따른다.
|
||||
@@ -19,8 +21,10 @@
|
||||
- 성공은 HTTP 200이며 envelope는 `success`, `message`, `data`, `errorProperty` 네 필드다. 클라이언트는 HTTP status와 `success`를 모두 확인한다. HTTP 200의 `success:false`도 실패다. 다른 HTTP 오류도 성공으로 처리하지 않는다.
|
||||
- 배너 객체: `id` 정수(JSON number, 불투명 ID로 앱의 정밀도 안전 전략 사용), `placement` enum, `imageUrl` 절대 http/https URL, `webUrl` string|null, `androidDeepLink` string|null, `iosDeepLink` string|null. 다른 배너 필드는 가정하지 않는다.
|
||||
- 공개 `SubBanner` DTO는 위 기본 필드 그대로이며 `startDate`/`endDate`/`isActive`를 추가하거나 가정하지 않는다. 서버는 활성 배너 중 현재 노출 기간 안인 항목 전체를 id 오름차순으로 `data.subBanners`에 반환하고, 결과가 없어도 배열을 `[]`로 반환한다. 앱은 그 목록에 기존 웹 URL/현재 OS 링크 필터를 적용한다. 응답 순서와 placement는 보존한다.
|
||||
- 두 추천의 `data.subBanners`는 국가별 언어 조건도 서버에서 적용한다. 기존 회원 국가 resolver의 강제 매핑이 우선하며 일반 회원·익명은 `CloudFront-Viewer-Country`를 사용하고 누락 시 KR이다. JP→JA, 그 외(KR·US 포함)→KO다. `Accept-Language`/`LangContext` 또는 기기 언어로 대체하지 않고 별도 language query나 클라이언트 언어 필터를 추가하지 않는다. 공개 DTO는 정확히 위 6필드이고 `lang`은 없다. EN은 관리자 저장·조회 가능하지만 현재 공개 노출되지 않는다.
|
||||
- 더 이상 사용하지 않을 별도 앱 요청은 `GET /api/v2/sub-banners`다. 앱에서 해당 endpoint를 호출하거나 대체용 두 번째 요청을 추가하지 않는다. 삭제된 경로의 구체적인 오류 status를 가정하지 않는다.
|
||||
- 기간 판단은 서버가 맡는다. 기기 시계로 기간을 다시 계산하거나 로컬 예약 timer를 추가하지 않는다.
|
||||
- 관리자 언어 계약은 생성 생략 KO·수정 생략 유지이며 null·비문자열·blank·unknown은 업로드/쓰기 전 400이다. 관리자 목록은 모든 언어다. 기존 KO backfill은 자동 언어 분류가 아니므로 운영 담당자가 JA 소재와 연결 이벤트 언어를 수동 검토한다. 앱은 이벤트 링크를 파싱해 언어를 추정하지 않고 외부 URL/딥링크 원문을 유지한다.
|
||||
- 서브 배너만을 위한 별도 fetch는 없다. 추천 API의 통신 실패는 기존 추천 화면의 오류 정책으로 처리하며 정상 `subBanners:[]`로 바꾸지 않는다. 개별 배너의 이미지 로딩·링크 실행 실패는 기존 추천 콘텐츠의 표시와 분리한다.
|
||||
|
||||
홈 추천 성공 응답 예시 (기존 추천 필드는 예시 데이터로 유지, 서브 배너 두 항목):
|
||||
@@ -94,6 +98,7 @@
|
||||
실제 앱 구조에 맞는 테스트를 추가한다. 최소 검증 범위:
|
||||
|
||||
- 모든 항목 표시, 응답 순서 유지, 홈/콘텐츠 placement 격리, 빈 목록에서 gap 없음.
|
||||
- JP와 KR·US·국가 누락 및 강제 매핑에서 서버가 선택한 목록을 그대로 소비하고 공개 6필드에 `lang`을 요구하지 않는지 확인한다.
|
||||
- URI 입력을 보존하면서 대상 OS 링크 우선, OS 링크 부재 시 웹, 딥링크 실패 시 웹 fallback 한 번, 양쪽 실패 시 비치명 상태.
|
||||
- 다른 OS 링크를 실행하지 않고 잘못된 scheme을 거부한다.
|
||||
- 비로그인 두 GET의 `data.subBanners`를 소비하며 별도 배너 요청이 발생하지 않는다. 추천 API 오류와 정상 빈 배열을 구분하고, 개별 이미지·링크 오류는 다른 추천 콘텐츠를 깨뜨리지 않는다.
|
||||
|
||||
Reference in New Issue
Block a user