test #449
@@ -0,0 +1,84 @@
|
|||||||
|
# Phase 3 리뷰 보고서
|
||||||
|
|
||||||
|
## 1. 리뷰 정보
|
||||||
|
|
||||||
|
| 항목 | 내용 |
|
||||||
|
|---|---|
|
||||||
|
| 대상 | Phase 3 `P3-T1`, `P3-T2`, `P3-R1`, `P3-GATE` |
|
||||||
|
| 기준 | HEAD `50409e41c0c469529572f5d77033c3cb23d67d22` + 현재 작업 트리 |
|
||||||
|
| 작업 트리 지문 | `3bbb1d90869484073c3af681118a13f5f03c3ccecbe84de16f1568338acd66b7` |
|
||||||
|
| 일자 / 리뷰어 | 2026-09-10 / Codex 및 문맥·목표·보안·QA 증거 리뷰어 |
|
||||||
|
| 기준 문서 | [PRD](../prd.md), [구현 계획](../plan-task.md), `docs/sample/sample-review.md` |
|
||||||
|
| 상태 | 판정 완료 |
|
||||||
|
|
||||||
|
## 2. 목적과 범위
|
||||||
|
|
||||||
|
`CCT-006~010`의 목록·미리보기·홈 표면, 저장 번역만 읽는 경계, 권한·페이지·공개 계약 유지를 확인한다.
|
||||||
|
기존 최종 Gate의 실제 실행 미완료 범위도 대조한다. 사용자 지시에 따라 테스트·컴파일·서버·HTTP는 실행하지 않는다.
|
||||||
|
|
||||||
|
## 3. 판정 기준과 코드 대조
|
||||||
|
|
||||||
|
아래 경로는 `src/main/kotlin/kr/co/vividnext/sodalive/` 기준이다.
|
||||||
|
|
||||||
|
| 표면 / 기준 | 코드 근거 | 판정 |
|
||||||
|
|---|---|---|
|
||||||
|
| 레거시 일반·최신 목록 | `explorer/profile/creatorCommunity/CreatorCommunityService.kt:305`, `:359`, `:641`, `:679` | 충족. 표시할 ID를 모아 번역 조회 후 본문만 복사 |
|
||||||
|
| v2 탭 | `v2/creator/channel/community/application/CreatorChannelCommunityQueryService.kt:74` | 충족. 반환 페이지 확정 후 번역 조회, 다음 페이지 확인용 추가 행 제외 |
|
||||||
|
| 채널 홈 고정·일반 | `v2/creator/channel/home/application/CreatorChannelHomeQueryService.kt:104`, `:133` → 공용 `findHomeCommunityPosts` | 충족. 두 그룹 모두 같은 읽기 연결 |
|
||||||
|
| 홈 추천 | `v2/recommendation/application/HomeRecommendationQueryService.kt:158` | 충족. 후보 정렬·중복 제거·limit 이후 최종 ID만 처리 |
|
||||||
|
| 팔로잉 소식 | `v2/home/following/application/HomeFollowingQueryService.kt:32`, `:60` | 충족. 커뮤니티 유형만 변경하고 다른 소식 유지 |
|
||||||
|
| 목록 계열 예약 금지 | `v2/creator/channel/community/translation/application/CreatorCommunityTranslationService.kt:33` | 충족. `findDisplayContents`는 읽기 전용이며 감지·예약·materialize 호출 없음 |
|
||||||
|
| 공개 스키마 | DTO/도메인 `copy(content = ...)` | 충족. 내부 `CreatorCommunityDisplayContent`를 공개 응답으로 추가하지 않음 |
|
||||||
|
| DDL 타입 정합성 | `schema.sql:11`, `CreatorCommunityTranslation.kt`의 sourceHash 매핑 | 기존 `P3-R1`의 VARCHAR(64) 수정 반영 확인 |
|
||||||
|
|
||||||
|
`LiveApiService`와 `ExplorerService`의 간접 목록 호출도 기존 서비스에 연결되어 저장 번역을 사용한다.
|
||||||
|
팔로잉 본문은 `DefaultHomeFollowingQueryRepository.kt:160`, `:251`에서 현재 게시물 내용을 읽으므로
|
||||||
|
소식 발행 당시 저장한 미리보기를 번역 원문으로 사용하지 않는다.
|
||||||
|
|
||||||
|
## 4. 테스트·기록 대조
|
||||||
|
|
||||||
|
test 경로는 `src/test/kotlin/kr/co/vividnext/sodalive/` 기준이다.
|
||||||
|
|
||||||
|
| 검증 대상 | 읽은 기존 테스트 |
|
||||||
|
|---|---|
|
||||||
|
| 배치 크기 1/4에서 SELECT 2회 유지 | `explorer/profile/creatorCommunity/CreatorCommunityTranslationEndToEndTest.kt:66`, `shouldReadTranslationsWithConstantSelectCountAcrossBatchSizes` |
|
||||||
|
| 목록 누락 번역의 작업/이벤트 미생성 | 같은 파일 `:98`, `shouldNotPublishOrScheduleWhenLegacyListReadsMissingTranslation` |
|
||||||
|
| 레거시 필터·마스킹·일괄 조회 | `explorer/profile/creatorCommunity/CreatorCommunityServiceTest.kt:579` 이후 관련 테스트 |
|
||||||
|
| v2 페이지 추가 행 제외·홈 두 그룹 | `v2/creator/channel/community/application/CreatorChannelCommunityQueryServiceTest.kt:180` 이후 관련 테스트 |
|
||||||
|
| 채널 홈 저장 번역 | `v2/api/creator/channel/home/CreatorChannelHomeEndToEndTest.kt:89`, `shouldUseStoredTranslationsForPinnedAndNormalHomeCommunityPosts` |
|
||||||
|
| 추천 최종 배치·팔로잉 커뮤니티 유형만 처리 | `v2/recommendation/application/HomeRecommendationQueryServiceTest.kt:705`, `v2/home/following/application/HomeFollowingQueryServiceTest.kt:123` |
|
||||||
|
|
||||||
|
`git diff`, `rg`, `sed`로 호출부와 테스트를 대조했다. 기존 XML과 레인 결과는 [증거 기록](review-evidence.md)에 있다.
|
||||||
|
이 표는 테스트를 새로 실행했다는 의미가 아니다. 기존 계획의 로컬 성공 기록과 실제 MySQL/Papago/HTTP 미완료 표기는
|
||||||
|
서로 구분되어 있으며, 후자를 완료한 것으로 평가하지 않는다.
|
||||||
|
|
||||||
|
## 5. 발견 사항 요약
|
||||||
|
|
||||||
|
**확정 발견 사항 없음.** 목록·채널 홈·추천·팔로잉의 저장 번역 적용은 인터뷰에서 확정한 범위에 부합한다.
|
||||||
|
|
||||||
|
## 6. 후보 판정
|
||||||
|
|
||||||
|
| 후보 | 판정 / 근거 |
|
||||||
|
|---|---|
|
||||||
|
| 추천·팔로잉 본문 복사가 유료 전체 본문을 노출 | 오탐. `DefaultHomeRecommendationQueryRepository.kt:893`, `DefaultHomeFollowingQueryRepository.kt:461`의 기존 무료 조건 유지 |
|
||||||
|
| 레거시/v2 마스킹 전에 원문 길이를 사용 | 오탐. 번역 본문을 복사한 뒤 `SelectCommunityPostResponse.kt:44`, `CreatorChannelCommunityQueryService.kt:253`의 기존 마스킹 실행 |
|
||||||
|
| 번역 배치 조회가 작성자별 N+1을 추가 | 오탐. `member` LAZY이며 읽기에서 접근하지 않는다. 서로 다른 작성자의 배치 크기 테스트가 기존에 존재 |
|
||||||
|
| 목록 번역 누락을 처리하기 위해 자동 작업 예약 | 오탐. 공용 읽기 메서드만 사용하고 예약 진입점을 호출하지 않음 |
|
||||||
|
|
||||||
|
## 7. 계획 전환
|
||||||
|
|
||||||
|
**전환 항목 없음.** 추가 수정 Task는 만들지 않는다. Phase 1 결함으로 번역이 아직 생성되지 않은 경우에는
|
||||||
|
이 Phase의 요구대로 원문을 표시한다. 예약 결함은 `P1-R4`에서 처리한다.
|
||||||
|
|
||||||
|
## 8. 리뷰 종료 판정
|
||||||
|
|
||||||
|
| 항목 | 결과 |
|
||||||
|
|---|---|
|
||||||
|
| 모든 합의된 목록·미리보기 표면 확인 | 충족 |
|
||||||
|
| 확정 결함 | 없음 |
|
||||||
|
| 후보 판정 완료 | 충족, 위 후보는 오탐 |
|
||||||
|
| 확정 항목 계획 반영 | 해당 없음 |
|
||||||
|
| 실행 범위·기존 미완료 검증 구분 | 충족 |
|
||||||
|
|
||||||
|
**최종 결론: Phase 3 기준 충족, 확정 발견 사항 없음.**
|
||||||
|
실제 DDL·MySQL 동시성·HTTP·Papago 확인은 기존 수동 체크리스트대로 남긴다. 이번 리뷰에서 제품 코드를 수정하지 않았다.
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# 2026-09-10 Phase별 정적 리뷰 증거
|
||||||
|
|
||||||
|
## 대상과 검증 범위
|
||||||
|
|
||||||
|
아래 지문부터 리뷰 산출물 검증까지는 최초 정적 리뷰 당시 기록이다. `P1-R4` 이후 변경에는 이 지문과 PASS를
|
||||||
|
소급 적용하지 않는다. 현재 최종 판정과 후속 자동 증거는 문서 끝에 별도로 누적한다.
|
||||||
|
|
||||||
|
- 기준 HEAD: `50409e41c0c469529572f5d77033c3cb23d67d22`.
|
||||||
|
- 리뷰 대상은 HEAD 자체가 아닌 현재 수정/미추적 source·test와 `schema.sql` 32개 파일이다.
|
||||||
|
- 위 파일의 경로순 `경로 + NUL + SHA256 + LF`를 결합한 SHA256:
|
||||||
|
`3bbb1d90869484073c3af681118a13f5f03c3ccecbe84de16f1568338acd66b7`.
|
||||||
|
- 사용자 지시: 컴파일·테스트는 이미 통과했으므로 테스트를 직접 실행하지 않는다.
|
||||||
|
- 이번 판정은 소스·테스트·기존 기록의 정적 대조다. 테스트/컴파일/서버/HTTP/Papago/MySQL 실행 판정이 아니다.
|
||||||
|
- 이전 리뷰의 PASS를 재사용하지 않고 현재 작업 트리를 다시 읽었다. 아래 PASS는 정적 리뷰 범위에만 적용한다.
|
||||||
|
|
||||||
|
## 레인 기록
|
||||||
|
|
||||||
|
모든 기록의 기준은 위 전체 HEAD와 작업 트리 지문이다. 소스가 바뀌면 이 결과를 그대로 재사용하지 않는다.
|
||||||
|
|
||||||
|
| 레인 | 판정 | 근거 / 결과 출처 |
|
||||||
|
|---|---|---|
|
||||||
|
| 보안·권한 `security_review` | PASS | 현재 본문 정합성, 번역 선택 후 유료 마스킹, 추천/팔로잉 무료 필터, 관리자 원문 보존 확인. `/root/security_review` 최종 보고, 2026-09-10. |
|
||||||
|
| 목표·제약 `goal_review` | 수정 필요 | Phase 1 캐시 경합으로 요청 target 유실을 독립 확인. Phase 2·3 추가 결함 없음. `/root/goal_review` 최종 보고, 2026-09-10. |
|
||||||
|
| 코드 품질·동시성 `code_review` | 수정 필요 | 감지 캐시 최초 INSERT 경합으로 후발 target 예약 유실. `/root/code_review` 최종 보고, 2026-09-10. Phase 1 보고서에 상세 근거를 기록한다. |
|
||||||
|
| 기존 QA 증거 `qa_evidence_review` | 정적 증거 확인 완료 | 기존 테스트 소스/XML 성공 기록을 확인했다. 실제 캐시 INSERT 경합과 한·영·일 전체 파이프라인의 직접 통합 증거 한계는 별도로 남긴다. `/root/qa_evidence_review` 최종 보고, 2026-09-10. |
|
||||||
|
| 문맥·통합 `context_review` | PASS — Phase 3 범위 | 목록/홈 및 간접 소비자, 공개 스키마·무료 필터·읽기 전용 경계 확인. `/root/context_review` 최종 보고, 2026-09-10. Phase 1·2 전체 판정으로 확대하지 않는다. |
|
||||||
|
|
||||||
|
동적 QA/debugging 감사는 사용자 지시에 따라 재실행하지 않았다. 이를 PASS나 신규 실패로 분류하지 않는다.
|
||||||
|
|
||||||
|
## 기존 실행 증거 표본
|
||||||
|
|
||||||
|
아래는 `build/test-results/test/`의 기존 XML을 읽은 결과이며 현재 턴에서 실행한 테스트가 아니다.
|
||||||
|
|
||||||
|
| XML 파일명 | 테스트 수 | 실패 / 오류 / skip | 기록 timestamp |
|
||||||
|
|---|---:|---|---|
|
||||||
|
| `TEST-kr.co.vividnext.sodalive.content.CreatorCommunityLanguageDetectTest.xml` | 12 | 0 / 0 / 0 | 2026-09-10T02:43:16 |
|
||||||
|
| `TEST-kr.co.vividnext.sodalive.v2.creator.channel.community.translation.CreatorCommunityTranslationServiceTest.xml` | 16 | 0 / 0 / 0 | 2026-09-10T02:50:05 |
|
||||||
|
| `TEST-kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityTranslationEndToEndTest.xml` | 4 | 0 / 0 / 0 | 2026-09-10T02:44:03 |
|
||||||
|
| `TEST-kr.co.vividnext.sodalive.i18n.translation.TranslationJobWorkerTest.xml` | 7 | 0 / 0 / 0 | 2026-09-10T02:44:03 |
|
||||||
|
| `TEST-kr.co.vividnext.sodalive.v2.api.creator.channel.community.adapter.in.web.CreatorChannelCommunityEndToEndTest.xml` | 15 | 0 / 0 / 0 | 2026-09-10T02:48:44 |
|
||||||
|
| `TEST-kr.co.vividnext.sodalive.v2.api.creator.channel.home.CreatorChannelHomeEndToEndTest.xml` | 2 | 0 / 0 / 0 | 2026-09-10T02:49:09 |
|
||||||
|
|
||||||
|
XML에 source 지문이 포함되어 있다고 가정하지 않는다. 사용자 보고와 계획의 과거 성공 기록을 보조하는 자료로만 사용한다.
|
||||||
|
|
||||||
|
## 최종 정적 판정
|
||||||
|
|
||||||
|
- [Phase 1](phase-1-review.md): 확정 수정 사항 1건 → `P1-R4`.
|
||||||
|
- [Phase 2](phase-2-review.md): 자체 구현 범위 충족, 추가 확정 발견 사항 없음. Phase 1 결함의 상세 예약 영향은 남는다.
|
||||||
|
- [Phase 3](phase-3-review.md): 저장 번역 표시·목록 비예약 범위 충족, 추가 확정 발견 사항 없음.
|
||||||
|
- 이번 리뷰는 테스트·제품 코드·DDL을 변경하지 않았다. Phase 1 수정과 실제 실행 검증은 후속 작업이다.
|
||||||
|
|
||||||
|
## 리뷰 산출물 검증
|
||||||
|
|
||||||
|
- `./gradlew tasks --all` — exit 0, `BUILD SUCCESSFUL`. 저장소 문서 가이드에 따른 task 목록 확인만 수행했다.
|
||||||
|
이 명령으로 컴파일이나 테스트를 실행하지 않았다.
|
||||||
|
- `git diff --check` — exit 0. 새 미추적 리뷰 문서는 별도 공백/개행 검사로 확인했다.
|
||||||
|
- 문서 링크·공백·템플릿 잔여값 검사 — 5개 문서 PASS. `P1-R4`는 Phase 1 안에 한 번만 미완료 Goal로 등록됐다.
|
||||||
|
- 리뷰 전후 source/test/DDL 32개 파일 SHA256 대조 — 동일 지문으로 PASS. 제품 코드·테스트·DDL 수정 없음.
|
||||||
|
|
||||||
|
## P1-R4 수정 후 증거 · 2026-09-10
|
||||||
|
|
||||||
|
이 절은 완료된 구현의 RED/GREEN·자동 회귀·리뷰 결과를 전달받아 동기화한 기록이다.
|
||||||
|
이번 문서 작업에서 제품 테스트를 다시 실행한 결과가 아니며, 위 최초 정적 리뷰의 지문을 새 코드의 지문으로 재사용하지 않는다.
|
||||||
|
|
||||||
|
### 구현과 RED/GREEN
|
||||||
|
|
||||||
|
- RED: 아래 focused 명령은 두 provider 진입 이후 exit 1로 실패했다.
|
||||||
|
`ExecutionException → DataIntegrityViolationException → H2 23505`로 감지 캐시 유일 키 충돌을 확인했다.
|
||||||
|
- GREEN: native MySQL `ON DUPLICATE KEY UPDATE id=id`와 scalar `SELECT ... FOR UPDATE`로 승자 행을
|
||||||
|
현재 읽기한다. native INSERT에 audit 시각을 명시하며 DB 예외를 잡고 후속 예약을 계속하지 않는다.
|
||||||
|
- 실제 캐시 service/repository를 통한 같은 게시물 `ja`/`en` 이중 miss와 다른 게시물의 동일 본문 경합을 검증했다.
|
||||||
|
캐시 1행으로 수렴하고 각 요청의 목표 언어 작업을 보존한다.
|
||||||
|
|
||||||
|
### 자동 검증 명령과 결과
|
||||||
|
|
||||||
|
RED focused 명령 (exit 1, 위 유일 키 충돌):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew test --tests 'kr.co.vividnext.sodalive.content.CreatorCommunityLanguageDetectionCacheConcurrencyTest' --tests 'kr.co.vividnext.sodalive.content.LanguageDetectionCacheServiceTest'
|
||||||
|
```
|
||||||
|
|
||||||
|
GREEN focused fresh 재실행, `BUILD SUCCESSFUL` (5분 19초):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew test --tests 'kr.co.vividnext.sodalive.content.CreatorCommunityLanguageDetectionCacheConcurrencyTest' --tests 'kr.co.vividnext.sodalive.content.LanguageDetectionCacheServiceTest' --rerun-tasks --no-parallel
|
||||||
|
```
|
||||||
|
|
||||||
|
P1 listener/scheduler/materializer 영향 회귀, `BUILD SUCCESSFUL` (1분 09초):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew test --tests 'kr.co.vividnext.sodalive.content.CreatorCommunityLanguageDetectTest' --tests 'kr.co.vividnext.sodalive.v2.creator.channel.community.translation.*' --tests 'kr.co.vividnext.sodalive.i18n.translation.*'
|
||||||
|
```
|
||||||
|
|
||||||
|
P2 상세/API 소비자 회귀, `BUILD SUCCESSFUL` (1분 42초):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew test --tests 'kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.*' --tests 'kr.co.vividnext.sodalive.v2.api.creator.channel.community.*'
|
||||||
|
```
|
||||||
|
|
||||||
|
형식 검사, `BUILD SUCCESSFUL` (44초):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./gradlew ktlintCheck
|
||||||
|
```
|
||||||
|
|
||||||
|
전체 `./gradlew test`는 생략했다. 공통 캐시 계약, 실제 repository 경합, 모든 직접 listener/scheduler/materializer
|
||||||
|
테스트와 P2 상세/API 소비자가 위 명령으로 통과했고 별도로 미해결된 공통 경계가 없었다.
|
||||||
|
과거 전체 빌드 성공을 이번 변경의 전체 테스트 실행으로 간주하지 않는다.
|
||||||
|
|
||||||
|
### 수정 후 리뷰와 현재 최종 판정
|
||||||
|
|
||||||
|
| 리뷰 | 판정 | 출처 |
|
||||||
|
|---|---|---|
|
||||||
|
| spec | PASS | `ses_f7657d350ffe3YUYhEHvHPuikK` |
|
||||||
|
| quality | APPROVED | `ses_f7656994dffeR2odTLswaw6RTo` |
|
||||||
|
|
||||||
|
**현재 최종 판정: 기존 Phase 1 결함 `REV-P1-007`은 `P1-R4` 로컬 자동 검증 범위에서 수정 완료다.**
|
||||||
|
H2 `MODE=MySQL` 결과는 실제 MySQL 8/InnoDB의 유일 키·격리 수준·audit 컬럼·잠금 동작 검증이 아니다.
|
||||||
|
테스트 서버의 순서 제어 이중 miss, 다른 게시물의 공유 캐시 수렴, provider 차단 중 본문 수정과 stale 결과 차단은
|
||||||
|
[계획의 수동 체크리스트](../plan-task.md)에 미완료로 남긴다. 실제 MySQL/Papago/live HTTP, Docker, 배포는
|
||||||
|
검증하지 않았으며 기존 정적 리뷰의 실환경 검증 한계도 유지한다.
|
||||||
Reference in New Issue
Block a user