docs(banner): 언어 필터 계약과 검증 결과를 기록한다
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
**Goal:** 관리자가 언어를 지정해 이벤트를 등록·식별하고, 앱 이벤트 목록과 팝업이 기존 국가 판정에 맞는 언어만 반환하게 한다.
|
||||
|
||||
**Architecture:** 기존 `Lang`과 `MemberContentPreferenceService.resolveCountryCode(member)`를 재사용한다. `EventRepository`에 nullable `lang` 조건을 추가해 두 앱 API는 KO/JA를 전달하고, 관리자 목록과 콘텐츠 메인 탭의 기존 내부 조회는 null을 전달해 언어 전체 조회를 유지한다.
|
||||
**Architecture:** 기존 `Lang`과 `MemberContentPreferenceService.resolveCountryCode(member)`를 재사용한다. 앱 목록·팝업은 KO/JA를 조회하고, Phase 3에서 콘텐츠 메인 탭 6곳도 회원 국가 판정에 따른 필수 언어를 조회한다. 관리자 목록은 언어 전체 조회를 유지한다.
|
||||
|
||||
**Tech Stack:** Kotlin, Java 17, Spring Boot 2.7.14, JPA/QueryDSL, JUnit 5, Mockito, MockMvc, Gradle Wrapper, MySQL
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
|
||||
| 문서 항목 | 내용 |
|
||||
|---|---|
|
||||
| 상태 | 구현 및 회귀 수정 완료 |
|
||||
| 상태 | Phase 3 후속 언어 필터 구현·전체 검증·독립 리뷰 완료, 미배포 |
|
||||
| 작성일 | 2026-08-19 |
|
||||
| 요구사항 기준 | `docs/20260819_이벤트_접속국가별_언어필터/prd.md` |
|
||||
| API 기준 | PRD 8절 |
|
||||
| 현재 Phase | Phase 2 완료 |
|
||||
| 현재 Phase | Phase 1~3 완료 |
|
||||
| 현재 활성 Goal | 없음 |
|
||||
| 다음 Goal | 없음 |
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
- 이벤트 수정 API와 레거시 `POST /event`의 요청 계약은 변경하지 않는다.
|
||||
- 기존 이벤트와 레거시 등록의 기본 언어는 `KO`다.
|
||||
- 관리자 목록은 기존 활성·종료 시각 조건을 유지하고 언어 조건을 추가하지 않는다.
|
||||
- `GET /event`, `GET /event/popup`만 `JP -> Lang.JA`, 그 외 `Lang.KO`를 사용한다.
|
||||
- `GET /event`, `GET /event/popup`과 Phase 3의 메인 탭 이벤트 배너는 `JP -> Lang.JA`, 그 외 `Lang.KO`를 사용한다.
|
||||
- 로그인 회원은 기존 강제 KR/JP 매핑을 유지하고, 비로그인·국가 누락은 기존 정규화·KR 기본값을 사용한다.
|
||||
- 콘텐츠 메인 탭 6곳의 `EventService.getEventList(isAdult)`는 언어 필터 없이 유지한다.
|
||||
- [과거 기준, `DEC-009`에서 정정] 콘텐츠 메인 탭 6곳은 원래 언어 필터 없이 조회했으나 이번 후속 Phase에서 국가별 언어 필터를 적용한다. 과거 P2 구현·검증 기록은 당시 상태로 보존한다.
|
||||
- 언어 필터는 QueryDSL `where`에서 정렬·`fetchFirst()` 전에 적용하고 메모리 후처리를 추가하지 않는다.
|
||||
- 신규 dependency·cache·resolver abstraction·관련 없는 refactoring을 추가하지 않는다.
|
||||
- 모든 구현 Task는 RED → RED 확인 → GREEN → GREEN 확인 → REFACTOR 순서를 지킨다.
|
||||
@@ -43,6 +43,7 @@
|
||||
|---:|---|---:|---|---|
|
||||
| 1 | 완료 | `3/3` | 없음 | 없음 |
|
||||
| 2 | 완료 | `2/2` + Gate + `P2-R1` | 없음 | 없음 |
|
||||
| 3 | 완료 | `1/1` + Gate | 없음 | 운영 배포 제외 |
|
||||
|
||||
- 동시에 하나의 미완료 goal만 운용한다.
|
||||
- 구현 완료 즉시 해당 Task 체크박스와 현재 상태를 갱신한다.
|
||||
@@ -58,13 +59,13 @@
|
||||
- 관리자 이벤트 목록 `lang` 응답과 언어 전체 조회
|
||||
- 앱 이벤트 목록·팝업의 접속 국가별 KO/JA 필터
|
||||
- 기존 강제 국가 매핑과 비로그인 KR 기본값 재사용
|
||||
- 콘텐츠 메인 탭 6곳의 언어 전체 조회 비회귀
|
||||
- P2 당시 콘텐츠 메인 탭 6곳의 언어 전체 조회 비회귀 기록. `DEC-009`로 후속 언어 필터가 승인되어 현재 Phase 3에서 대체한다.
|
||||
|
||||
### 제외
|
||||
|
||||
- 이벤트 수정 시 언어 변경
|
||||
- 레거시 `POST /event`의 `lang` request parameter
|
||||
- 콘텐츠 메인 탭 6곳의 국가별 이벤트 필터
|
||||
- 과거 제외 범위: 콘텐츠 메인 탭 6곳의 국가별 이벤트 필터. `DEC-009` 후속 승인으로 현재 범위에 포함하며 과거 체크박스·검증은 당시 이력으로 유지한다.
|
||||
- EN 이벤트를 반환할 앱 국가 정책
|
||||
- 다른 언어 fallback, `Accept-Language` 판정, 신규 dependency·공통 abstraction
|
||||
- 기존 이벤트 성인·활성·게시 기간·정렬·URL 정책 변경
|
||||
@@ -82,6 +83,7 @@
|
||||
| `EVENT-LANG-007` | `P2-T2` | `lang = null`의 KO/EN/JA 전체 조회 mutation RED·GREEN |
|
||||
| `EVENT-LANG-008` | `P1-T1`, `P1-GATE` | KO 기본 저장 테스트와 KO backfill DDL 대조 |
|
||||
| `EVENT-LANG-009` | `P2-T1`, `P2-GATE` | QueryDSL `where` 조건과 정렬·`fetchFirst()` 선행 검증 |
|
||||
| `EVENT-LANG-010` | `P3-T1`, `P3-GATE` | 여섯 메인 탭의 JP→JA/그 외→KO HTTP·service 검증 및 기존 `isAdult` 계산 비회귀 |
|
||||
|
||||
## 파일 구조
|
||||
|
||||
@@ -832,3 +834,67 @@ P1-T1 → P1-T2 → P1-GATE → P2-T1 → P2-T2 → P2-GATE → P2-R1
|
||||
- 전체 회귀를 실행하지 않았으면 생략 근거와 대신 실행한 focused·직접 영향 명령을 적는다.
|
||||
- 남은 항목과 갱신한 PRD·plan·review 경로를 적는다.
|
||||
- 성공을 추정하지 않고 실제 실행한 최신 검증 결과와 완료되지 않은 범위를 함께 전달한다.
|
||||
|
||||
## Phase 3: 콘텐츠 메인 탭 이벤트 언어 필터 후속
|
||||
|
||||
2026-11-02 승인에 따라 과거 `EVENT-LANG-007`의 언어 미필터 요구를 정정한다. P2 완료 체크박스와 검증 기록은 당시 요구 범위의 이력이며 되돌리지 않는다.
|
||||
|
||||
### Task 3.1 여섯 메인 탭의 국가별 이벤트 언어 조회
|
||||
|
||||
**Goal `P3-T1`:** 콘텐츠 메인 탭 여섯 `eventBannerList`가 기존 회원 국가 판정에 따른 JA 또는 KO 이벤트만 조회하고 기존 성인 계산을 유지한다.
|
||||
|
||||
- 시작 조건: `DEC-009`, `EVENT-LANG-010` 승인.
|
||||
- 완료 증거: 기준 테스트의 사전 통과 기록, RED에서 국가별 언어·기존 성인 조건 assertion 실패, GREEN focused 통과, 실제 HTTP 경로 검증, 전체 회귀·ktlint·bootJar 및 독립 리뷰 결과.
|
||||
- 범위 밖: 이벤트 상세·팝업 정책, 메인 탭 응답 DTO/URL 변경, 링크·이벤트 파싱, 새 dependency, 운영 DDL 실행, UI 및 기존 성인 계산 변경.
|
||||
- **Files:**
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/content/main/tab/alarm/AudioContentMainTabAlarmService.kt`
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/content/main/tab/replay/AudioContentMainTabLiveReplayService.kt`
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/content/main/tab/series/AudioContentMainTabSeriesService.kt`
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/content/main/tab/asmr/AudioContentMainTabAsmrService.kt`
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/content/main/tab/content/AudioContentMainTabContentService.kt`
|
||||
- Modify: `src/main/kotlin/kr/co/vividnext/sodalive/content/main/tab/home/AudioContentMainTabHomeService.kt`
|
||||
- Verify/reuse (변경 불필요): `src/main/kotlin/kr/co/vividnext/sodalive/event/EventService.kt`, `src/main/kotlin/kr/co/vividnext/sodalive/event/EventRepository.kt`
|
||||
- Test: `src/test/kotlin/kr/co/vividnext/sodalive/event/EventServiceTest.kt`, `src/test/kotlin/kr/co/vividnext/sodalive/event/EventRepositoryTest.kt`, `src/test/kotlin/kr/co/vividnext/sodalive/event/EventBannerLanguageIntegrationTest.kt` (new; actual HTTP coverage for the six main-tab endpoints)
|
||||
- Baseline/related HTTP regression: `src/test/kotlin/kr/co/vividnext/sodalive/content/main/tab/home/AudioContentMainTabHomeServiceIntegrationTest.kt`, `src/test/kotlin/kr/co/vividnext/sodalive/event/EventControllerIntegrationTest.kt`
|
||||
- **Interfaces:** reuse `MemberContentPreferenceService.resolveCountryCode(member)` and existing `Lang`; each current caller supplies member-derived language while retaining its existing `isAdult` value. Repository language is non-null on these six paths; existing low-level callers without requested filtering retain their nullable contract. No public response field is added.
|
||||
- [x] **Baseline:** 부모의 사전 통과 113개 중 기존 `EventServiceTest`, `EventRepositoryTest`, `EventControllerIntegrationTest`, `AudioContentMainTabHomeServiceIntegrationTest` 15개를 재사용했다. 원본: `/tmp/soda-banner-ulw.HDkpg4/baseline.log`.
|
||||
- [x] **RED:** 여섯 실제 HTTP 경로가 실제 EventService/Repository를 사용하도록 mixed KO/JA/EN 및 성인 true/false/null 행을 추가했다. 국가별 언어와 기존 성인 조건을 응답 ID로 검증한다.
|
||||
- [x] **RED 확인:** 신규 HTTP 7개 모두 언어 미필터 assertion으로 실패했다. 컴파일·설정 실패가 아니다. `/tmp/soda-banner-impl.CfAkhD/event-red.log`, `event-red.xml`.
|
||||
- [x] **GREEN:** 여섯 기존 호출부에 member 국가로 선택한 `Lang`만 추가했다. 기존 성인 계산식·EventService/Repository production code·공개 DTO는 변경하지 않았다.
|
||||
- [x] **GREEN 확인:** focused 22개가 실패·오류·무시 0으로 통과했다. JP/KR/US/누락, 성인 설정 false/true, 강제 JP/KR 회원 및 익명 홈을 실제 HTTP 64건으로 확인했다.
|
||||
- [x] **REFACTOR:** 전체 2,928개 테스트, 공백 수정 후 영향 26개 HTTP 테스트·전체 ktlint·bootJar 및 독립 리뷰를 확인했다. 운영 DDL은 실행하지 않았다.
|
||||
|
||||
```bash
|
||||
export TMPDIR=/tmp/soda-banner-impl.CfAkhD NODE_COMPILE_CACHE=/tmp/soda-banner-impl.CfAkhD/node-compile-cache BUN_RUNTIME_TRANSPILER_CACHE_PATH=/tmp/soda-banner-impl.CfAkhD/bun-transpiler
|
||||
./gradlew test --tests 'kr.co.vividnext.sodalive.event.EventServiceTest' --tests 'kr.co.vividnext.sodalive.event.EventRepositoryTest' --tests 'kr.co.vividnext.sodalive.event.EventBannerLanguageIntegrationTest' --tests 'kr.co.vividnext.sodalive.event.EventControllerIntegrationTest' --tests 'kr.co.vividnext.sodalive.content.main.tab.home.AudioContentMainTabHomeServiceIntegrationTest' --console=plain --no-daemon -Pkotlin.compiler.execution.strategy=in-process
|
||||
./gradlew test ktlintCheck bootJar --continue --console=plain
|
||||
```
|
||||
|
||||
**Expected:** focused tests exercise real country-to-language and HTTP paths; full suite, lint, and bootJar exit 0. LSP diagnostics are unavailable in this environment and must be reported as not run, not as passing.
|
||||
|
||||
### Phase 3 Gate `P3-GATE`
|
||||
|
||||
- 시작 조건: `P3-T1` 완료.
|
||||
- 완료 증거: six-caller diff confirms preserved `isAdult`, real HTTP tests show country language filtering, focused/full tests and lint/build pass, independent review has no unresolved blocker.
|
||||
- 범위 밖: UI, production DB/DDL execution, event detail/adult policy changes.
|
||||
- [x] 여섯 호출부·반환 언어·공개 DTO 불변을 확인하고 P1/P2 이력을 보존했다. 전체 검증 및 최종 Oracle 승인으로 Gate를 완료했다.
|
||||
|
||||
### Phase 3 구현 Progress, 2026-11-02
|
||||
|
||||
- 현재 `test` 브랜치/HEAD `7fce26ad`에서 구현했으며 worktree·commit·stage·push는 하지 않았다. 기존 P1/P2 기록과 부모가 승인한 PRD 변경은 보존했다.
|
||||
- RED 명령은 위 focused 명령에서 `--tests 'kr.co.vividnext.sodalive.event.EventBannerLanguageIntegrationTest'` 하나만 선택했다. JP의 예상 2개 대신 KO/EN까지 6개가 반환되는 assertion 실패 7건을 확인했다. 로그 `event-red.log`, 원본 HTTP/XML `event-red.xml`은 모두 `/tmp/soda-banner-impl.CfAkhD/` 아래에 있다.
|
||||
- GREEN은 위 focused 명령이며 `event-green-retry.log`에 `BUILD SUCCESSFUL in 4m 15s`가 남는다. Service 4, Repository 5, 기존 Controller 5, 신규 Banner HTTP 7, 기존 Home HTTP 1로 총 22개가 통과했다. 첫 `event-green.log` 실행은 test compilation 중 600초 도구 제한으로 종료되어 통과 근거로 사용하지 않았다. 프로세스 종료 확인 후 제한을 늘려 순차 재실행했다.
|
||||
- 실제 JWT/랜덤 포트/H2 Event 행/기존 resolver를 사용했다. 여섯 경로 각각 10개 국가·성인·강제 매핑 조합과 익명 홈 4개를 확인했고 `Accept-Language: en`에도 국가 기준 언어가 선택됐다. `event-http-evidence.log`의 64건과 `event-green.xml`에 실제 상태·본문이 남으며 토큰은 출력하지 않았다.
|
||||
- 구현 및 focused/HTTP 범위만 완료했다. 사용자 지정 종료 경계에 따라 전체 suite·ktlint·bootJar·독립 리뷰와 `P3-GATE`는 부모 작업으로 미완료 유지한다. LSP 진단 도구는 없어 실행하지 않았다. 구현 보고서: `/tmp/soda-banner-impl.CfAkhD/implementation-report.md`.
|
||||
- 최종 source 상태에서 위 5개 클래스와 Phase 7의 6개 클래스를 하나의 focused 명령으로 순차 재검증했다. `final-focused.log`: `BUILD SUCCESSFUL in 8m 8s`, 11개 클래스 145개, 실패·오류·무시 0. 최종 원본은 같은 root의 `final-TEST-*.xml`, 실제 HTTP 본문은 `final-http-db-evidence.log`다. 전체 suite 실행은 아니다.
|
||||
|
||||
### Phase 3 최종 검증 Progress, 2026-11-03
|
||||
|
||||
- 부모 실행: `./gradlew test ktlintCheck bootJar --continue --console=plain --no-daemon -Pkotlin.compiler.execution.strategy=in-process`. 전체 XML 집계는 336 suites / 2,928 tests / failures=0 / errors=0 / skipped=0이며 `bootJar`도 성공했다. 최초 명령은 서브 배너 테스트 팩토리 인자 줄바꿈 한 곳의 ktlint 오류로 exit 1 (15m 50s)이었다. 테스트 실패나 제품 코드 오류는 아니었다.
|
||||
- 해당 테스트 인자 여섯 개를 값·순서 변경 없이 줄별로 배치한 뒤 `./gradlew test --tests 'kr.co.vividnext.sodalive.v2.subbanner.adapter.in.web.RecommendationSubBannerIntegrationTest' ktlintCheck bootJar --continue --console=plain --no-daemon -Pkotlin.compiler.execution.strategy=in-process`를 실행했다. exit 0, `BUILD SUCCESSFUL in 4m 32s`, 26 tests / failures=0 / errors=0 / skipped=0, 전체 lint 통과, bootJar UP-TO-DATE다.
|
||||
- 전체 회귀 후 변경은 테스트의 공백뿐이므로 전체 2,928개를 다시 실행하지 않고 영향받은 26개 HTTP 시나리오를 재실행했다. 최신 `build/test-results/test`와 HTML은 이 26개 실행으로 갱신됐다. 전체 집계는 갱신 전 부모가 직접 확인한 기록이다.
|
||||
- 부모는 전체 실행으로 실제 HTTP 테스트를 다시 구동하고 두 추천의 JP/KR/US/누락·강제 국가, 기간·소프트 삭제·공개 6필드 재검증 결과를 확인했다. 제품 JAR: `build/libs/sodalive-0.0.1-SNAPSHOT.jar`.
|
||||
- LSP 도구 부재로 미실행이며 Gradle Kotlin compile 및 ktlint를 대체 진단으로 사용했다. 기존 무관 파일의 컴파일/Gradle 경고와 H2 scheduler의 MySQL 문법 로그는 테스트 실패와 구분하며 수정하지 않았다.
|
||||
- 원본 로그는 실행 당시 `/tmp/soda-banner-ulw.HDkpg4/full-verification.log`, `final-verification.log`에 보관했다. 소유 임시 자료는 종료 시 정리하고 핵심 결과는 본 기록과 [공동 리뷰](../20261029_가로형서브배너/reviews/banner-language-review.md)에 보존한다.
|
||||
- 독립 Oracle 리뷰는 명세·코드·시나리오를 승인했고, 후속 공백 delta와 최종 검증 증거도 APPROVE했다. 미해결 발견 사항 없음. `P3-T1/P3-GATE` 완료이며 운영 배포는 별도다.
|
||||
- 메인 탭 구현·테스트 커밋 `255da2b6`, hook/메시지 검사 통과. 소유 QA 프로세스와 임시 경로 정리는 공동 리뷰의 종료 증거에 기록했다. 운영 배포·push는 하지 않았다.
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 문서 상태 | 구현 기준 확정 |
|
||||
| 문서 상태 | Phase 3 메인 탭 후속 언어 필터 구현·전체 검증·독립 리뷰 완료, 미배포 |
|
||||
| 작성일 | 2026-08-19 |
|
||||
| 최종 수정일 | 2026-08-20 |
|
||||
| 최종 수정일 | 2026-11-03 |
|
||||
| 대상 제품 | 관리자 이벤트 배너, 앱 이벤트 목록·팝업 |
|
||||
| 작성자·결정권자 | 사용자 |
|
||||
| 관련 API Contract | 별도 문서 없음. 이 문서 8절을 기준으로 사용 |
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
- 이벤트 수정 API에서 `lang`을 변경하지 않는다.
|
||||
- `EventController.createEvent`의 `POST /event` 요청 계약을 변경하지 않는다.
|
||||
- 콘텐츠 메인 탭 6곳이 `EventService.getEventList(isAdult)`로 조립하는 `eventBannerList`에 언어 필터를 적용하지 않는다.
|
||||
- [2026-11-02 정정, DEC-009] 콘텐츠 메인 탭 6곳의 `eventBannerList`는 Phase 2 당시 언어 필터 제외 결정의 범위였으나, 이번 후속 요구로 각 호출에 기존 접속 국가 판정에 따른 언어 필터를 적용한다. 과거 구현·검증 기록은 당시 범위로 보존한다.
|
||||
- `Lang`에 새 enum을 추가하거나 `EN`을 노출할 접속 국가 정책을 추가하지 않는다.
|
||||
- `Accept-Language`를 이벤트 언어 판정에 사용하지 않는다.
|
||||
- 요청 언어의 이벤트가 없을 때 다른 언어로 fallback하지 않는다.
|
||||
@@ -92,9 +92,10 @@
|
||||
| `EVENT-LANG-004` | 확정 | `GET /event`는 판정 국가가 JP이면 JA, 그 외에는 KO 이벤트만 반환한다. | 서로 다른 언어의 활성 이벤트가 함께 있어도 판정 언어만 `eventList`에 있다. | `P2-T1` |
|
||||
| `EVENT-LANG-005` | 확정 | `GET /event/popup`은 판정 국가가 JP이면 JA, 그 외에는 KO 팝업만 반환한다. | 다른 언어 팝업의 ID가 더 최신이어도 언어 필터 후 선택된 팝업을 반환한다. | `P2-T1` |
|
||||
| `EVENT-LANG-006` | 확정 | 로그인 회원은 기존 강제 KR/JP 매핑을 포함한 국가 판정을 사용한다. | 강제 JP 회원은 비JP 헤더에서도 JA, 강제 KR 회원은 JP 헤더에서도 KO를 선택한다. | `P2-T1` |
|
||||
| `EVENT-LANG-007` | 확정 | 콘텐츠 메인 탭의 기존 `eventBannerList`는 언어 필터 없이 조회한다. | `getEventList(isAdult)` 경로가 `lang = null`을 유지하고 KO/JA/EN 모두를 조회할 수 있다. | `P2-T2` |
|
||||
| `EVENT-LANG-007` | 과거 요구, `DEC-009`에서 정정 | Phase 2 당시 콘텐츠 메인 탭 `eventBannerList`는 언어 필터 없이 조회하도록 확정했다. 이 요구는 `EVENT-LANG-010`으로 대체됐으며 현재 적용하지 않는다. | P2 당시 `lang = null`의 전체 언어 조회를 검증한 완료 증거는 역사적 기록으로 보존한다. | `P2-T2` (당시), `P3-T1` (대체) |
|
||||
| `EVENT-LANG-008` | 확정 | 기존 이벤트와 레거시 등록 경로의 언어는 KO다. | 기존 row를 KO로 backfill하고 `NOT NULL DEFAULT 'KO'`를 적용하며 `POST /event`에 `lang`을 추가하지 않는다. | `P1-T1` |
|
||||
| `EVENT-LANG-009` | 확정 | 앱 언어 필터는 DB 조회 조건으로 적용한다. | QueryDSL `where` 내 `event.lang.eq(lang)`이 정렬·`fetchFirst()` 전에 적용된다. | `P2-T1` |
|
||||
| `EVENT-LANG-010` | 확정, 2026-11-02 후속 | 콘텐츠 메인 탭 6곳의 `eventBannerList`도 접속 국가별 이벤트 언어를 조회한다. | 기존 `resolveCountryCode(member)` 결과가 JP이면 JA, 그 외에는 KO만 반환하며 각 호출부의 기존 `isAdult` 계산과 응답 계약은 유지한다. | `P3-T1`, `P3-GATE` |
|
||||
|
||||
## 8. API 계약
|
||||
|
||||
@@ -155,7 +156,8 @@
|
||||
- [x] 판정 국가 JP에서 `GET /event`, `GET /event/popup`이 JA만 반환한다. (`EVENT-LANG-004~006`)
|
||||
- [x] JP 이외와 국가 누락에서 두 API가 KO만 반환한다. (`EVENT-LANG-004`, `EVENT-LANG-005`)
|
||||
- [x] 다른 언어의 최신 팝업이 있어도 언어 필터 후 선택된 팝업이 반환된다. (`EVENT-LANG-005`, `EVENT-LANG-009`)
|
||||
- [x] 콘텐츠 메인 탭 6곳의 기존 `eventBannerList`는 언어 필터 없이 조회된다. (`EVENT-LANG-007`)
|
||||
- [x] Phase 2 당시 콘텐츠 메인 탭 6곳의 `eventBannerList`가 언어 필터 없이 조회됨을 검증했다. 이는 당시 요구에 대한 완료 이력이다. (`EVENT-LANG-007`)
|
||||
- [x] 후속 요구: 콘텐츠 메인 탭 6곳의 `eventBannerList`가 JP→JA, 그 외→KO만 조회하며 기존 `isAdult` 계산을 유지한다. (`EVENT-LANG-010`, `P3-T1`, `P3-GATE`; 2026-11-03 전체 2,928개 및 실제 HTTP 검증 완료)
|
||||
- [x] 기존 성인·활성·게시 기간·정렬·URL·응답 스키마 정책이 유지된다.
|
||||
|
||||
### 11.1 구현 완료 검증 — 2026-08-20
|
||||
@@ -180,6 +182,7 @@
|
||||
| `EVENT-LANG-001~003`, `EVENT-LANG-008` | 1 | `P1-T1`, `P1-T2`, `P1-GATE` | 엔티티·관리자 controller/service/repository 통합 테스트 |
|
||||
| `EVENT-LANG-004~006`, `EVENT-LANG-009` | 2 | `P2-T1`, `P2-GATE` | `EventServiceTest`, `EventRepositoryTest`, `EventControllerIntegrationTest` |
|
||||
| `EVENT-LANG-007` | 2 | `P2-T2`, `P2-GATE` | 언어 없는 기존 서비스 호출과 Repository null 조건 비회귀 테스트 |
|
||||
| `EVENT-LANG-010` | 3 | `P3-T1`, `P3-GATE` | 여섯 호출부의 국가별 language filter, adult 조건 비회귀, 실제 HTTP 테스트 |
|
||||
|
||||
## 14. Decision Log
|
||||
|
||||
@@ -193,6 +196,7 @@
|
||||
| 2026-08-19 | `DEC-006` | 확정 | 기존 이벤트는 KO로 backfill하고 `NOT NULL DEFAULT 'KO'`를 적용한다. | 사용자 인터뷰 A, 기존 배너 DDL 패턴 | `EVENT-LANG-008`, `P1-T1` |
|
||||
| 2026-08-19 | `DEC-007` | 확정 | 언어 입력은 `AdminEventBannerController`에만 추가하고 레거시 `POST /event`는 KO 기본값을 사용한다. | 사용자 인터뷰 A | `EVENT-LANG-002`, `EVENT-LANG-008`, `P1-T1~T2` |
|
||||
| 2026-08-20 | `DEC-008` | 확정 | `GET /event`의 익명 접근은 유지하고 `GET /event/popup`은 기준 HEAD의 인증 필수 정책을 유지한다. | 구현 리뷰에서 언어 필터와 무관한 익명 공개 확장을 확인 | `EVENT-LANG-005`, `P2-R1` |
|
||||
| 2026-11-02 | `DEC-009` | 정정 | 기존 콘텐츠 메인 탭 6곳의 언어 미필터 요구를 대체한다. 각 `eventBannerList` 호출은 기존 회원 국가 판정 `resolveCountryCode(member)`를 사용해 JP→JA, 그 외→KO로 필터링한다. 기존 `isAdult` 계산, 응답 계약 및 과거 구현 기록은 보존한다. | 승인된 최소 후속 언어 수정 | `EVENT-LANG-007`의 과거 범위, `EVENT-LANG-010`, `P3-T1` |
|
||||
|
||||
## 15. 변경 관리
|
||||
|
||||
@@ -202,3 +206,10 @@
|
||||
2. 관련 요구사항·수용 기준·API 계약을 갱신한다.
|
||||
3. `plan-task.md`의 범위·Files·Interfaces·체크박스를 코드 변경 전에 먼저 갱신한다.
|
||||
4. 기존 Progress·검증 기록을 삭제하거나 덮어쓰지 않는다.
|
||||
|
||||
## 16. 후속 요구사항: 메인 탭 이벤트 언어 — 2026-11-02
|
||||
|
||||
- 승인된 변경은 콘텐츠 메인 탭의 기존 `eventBannerList`를 조립하는 6개 호출부에만 적용한다. 접속 국가 판정은 기존 `MemberContentPreferenceService.resolveCountryCode(member)`를 재사용해 `JP`는 `Lang.JA`, 그 외는 `Lang.KO`로 변환한다.
|
||||
- 기존 각 호출부의 `isAdult` 계산과 성인 필터 동작은 변경하지 않는다. 언어 조건은 기존 Event Repository 조회 경로에서 DB 조건으로 적용한다.
|
||||
- 이벤트 상세, 팝업/API 이외 정책, 공개 응답 DTO·URL 처리, 이벤트 연결 파싱은 변경하지 않는다. 새 dependency와 별도 resolver를 추가하지 않는다.
|
||||
- 관련 성공 기준·추적표는 `EVENT-LANG-010` 및 `P3-T1`/`P3-GATE`에 연결한다. 과거 `EVENT-LANG-007`과 완료된 P2 증거는 당시 언어 전체 조회 계약의 기록이며 현재 메인 탭 요구사항을 지배하지 않는다.
|
||||
|
||||
Reference in New Issue
Block a user