feat(ai-character): 수정 요청 변경 필드만 전송

This commit is contained in:
Yu Sung
2026-08-06 23:47:09 +09:00
parent 2a04955bd7
commit dcc344764b
18 changed files with 1695 additions and 120 deletions

View File

@@ -0,0 +1,239 @@
# Phase 1 변경 필드 요청 코드 리뷰
## 1. 리뷰 정보
| 항목 | 내용 |
|---|---|
| 리뷰 대상 | Phase 1 / `P1-T1`~`P1-T5`, `P1-GATE` |
| 기준 commit 또는 working tree | 미커밋 working tree (`git status --short` 기준 기능 코드 14개 수정, 기능 문서 디렉터리 신규) |
| 리뷰 일자 | 2026-08-06 |
| 리뷰어 | Codex |
| 기준 문서 | [prd.md](../prd.md), [api-contract.md](../api-contract.md), [plan-task.md](../plan-task.md) |
| 리뷰 상태 | 수정 검증 완료 |
## 2. 리뷰 목적과 범위
### 목적
- 다섯 수정 기능이 최종 변경 field와 교체 file만 전송하는지 확인한다.
- 무변경 차단, 기존 직렬화, 전용 mutation 제외와 계획의 완료 기록이 실제 코드·test와 일치하는지 확인한다.
### 포함 범위
- 코드: `src/features/characters`, `src/features/audio-contents`, `src/features/community-posts`, `src/features/series`, `src/features/fan-talks`의 수정 form·serializer·API 경계
- 테스트: 위 다섯 feature의 Vitest 전체와 관련 mock Chromium E2E 계획
- 문서: `DIFF-001~005`, `CHAR-001`, `AUDIO-001`, `COMM-001`, `SERIES-001`, `FANTALK-001`, `FILE-001`, `DATA-001~002`, Phase 1 Task·Gate
- 수동 검증: payload와 disabled 상태는 component test와 mock E2E로 대체하며 별도 실서버 Network 검증은 수행하지 않는다.
### 제외 범위
- 생성, 비활성화, 커뮤니티 고정, 시리즈 순서 변경, FanTalk 원글 삭제의 신규 동작
- backend DTO·저장 로직, 새 field·file 삭제·원작 연결 해제
- 관련 없는 화면·성능·스타일 리팩터링
## 3. 판정 기준
### 심각도
| 심각도 | 기준 |
|---|---|
| Blocker | 보안·데이터 손실 위험, 핵심 흐름 불능, 완료 판정을 무효화하는 문제 |
| High | 확정 요구사항·API Contract 위반 또는 주요 회귀 |
| Medium | 제한된 조건에서 발생하는 기능·접근성·복구 문제 |
| Low | 유지보수성, 문서 정합성 또는 비핵심 UX 문제 |
### 상태
| 상태 | 의미 | 후속 처리 |
|---|---|---|
| 후보 | 근거를 발견했지만 아직 재현·판정하지 않음 | 검증 후 상태 변경 |
| 확정 | 코드·test·문서 근거로 문제가 확인됨 | `plan-task.md` 회귀 수정 Task 후보 |
| 오탐 | 요구사항이나 실행 결과상 문제가 아님 | 근거를 남기고 종료 |
| 보류 | 외부 계약·환경·제품 결정이 필요함 | 담당 주체와 재개 조건 기록 |
| 수정 완료 | 수정과 관련 검증이 완료됨 | 실행 명령과 결과 연결 |
## 4. 검토한 근거
### 문서와 코드
- 요구사항: `DIFF-001~005`, 기능별 `CHAR-001`~`FANTALK-001`, `FILE-001`, `DATA-001~002`
- API Contract: §1 변경 판정·생략·file, §2.1~§2.5 기능별 payload, §4 회귀 보호
- 계획: `P1-T1`~`P1-T5`, `P1-GATE`
- 코드: 다섯 feature의 form·serializer·API helper와 `CommunityPostSheet.tsx:32-42`
- 테스트: 다섯 feature test 디렉터리 전체, `community-sheet.test.tsx`
### 실행 환경
```text
OS: Darwin 25.0.0 x86_64
Node: v24.12.0
npm: 11.7.0
Browser/viewport: Playwright mock Chromium, 대상 spec의 desktop·tablet·mobile viewport
환경 변수: Vitest 기본 test mode, 민감정보 기록 없음
```
### 실행한 검증
| 명령 또는 수동 검증 | 결과 | 핵심 증거 |
|---|---|---|
| `npm run test:run -- src/features/characters src/features/audio-contents src/features/community-posts src/features/series src/features/fan-talks` | 성공 | exit 0, 35 files / 227 tests 통과. 아래 경계 test가 없어 결함을 검출하지 못함 |
| 다섯 기능 form·serializer·test 정적 대조 | 실패 | Community만 outgoing raw `content`와 trim 비교가 불일치 |
| 실서버 DevTools Network | 불가 | test 환경 리뷰이며 인증된 실서버를 사용하지 않음. component multipart assertion으로 대체 예정 |
## 5. 발견 사항 요약
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|---|---|---|---|---|---|
| `REV-P1-001` | High | 수정 완료 | Community content의 비교와 전송 직렬화가 달라 공백 변경이 누락됨 | `P1-T3``P1-R1` | `P1-R1` 완료 |
| `REV-P1-002` | Low | 수정 완료 | 완료된 Phase 1과 PRD 성공 기준 상태가 불일치함 | `P1-GATE``P1-R2` | `P1-R2` 완료 |
## 6. 발견 사항 상세
### REV-P1-001 — Community content의 비교와 전송 직렬화가 달라 공백 변경이 누락됨
- **심각도:** High
- **상태:** 수정 완료
- **관련 요구사항:** `DIFF-001`, `DIFF-002`, `DIFF-004`, `COMM-001`
- **관련 계약:** API Contract §1.2, §1.4, §2.3
- **소유 Task:** `P1-T3``P1-R1`
**관찰 내용**
Community update는 기존과 같이 form의 `content` 원문을 request에 넣지만, 변경 여부만 현재 값과 기준값을 각각 `trim()`해 비교한다. 따라서 기존 내용 앞뒤에 공백만 추가하거나 제거하면 실제 전송 값은 달라졌어도 request에서 `content`가 생략되고 저장 button이 disabled된다.
**근거**
- 코드: `src/features/community-posts/components/CommunityPostSheet.tsx:33-35`는 trim 비교 후 raw `content`를 할당한다.
- 기존 코드: 구현 전 `savePost``{ content, ... }`로 원문을 전송했으며 update용 schema도 trim 변환을 하지 않는다.
- 테스트: `src/features/community-posts/tests/community-sheet.test.tsx`에는 무변경·일반 content 변경 test는 있지만 공백 경계 test가 없다.
- 문서: PRD `DIFF-002`와 API Contract §1.2는 현재 값과 기준값에 같은 기존 직렬화 규칙을 적용하도록 요구한다.
**재현 또는 검증 절차**
1. `post.content``오늘의 상담 기록입니다.`인 Community Sheet를 연다.
2. textarea 값을 ` 오늘의 상담 기록입니다. `로 바꾼다.
3. 실제 결과: 두 값을 trim해 같다고 판정하므로 `수정 저장`이 disabled이고 request는 0건이다.
4. 요구 결과: 기존 update의 raw content 직렬화를 유지해 저장이 enabled되고 request는 `{ "content": " 오늘의 상담 기록입니다. " }`다.
**영향**
관리자가 게시글 내용의 앞뒤 공백을 의도적으로 변경해도 저장할 수 없으며, payload와 disabled가 동일한 직렬화 결과를 사용한다는 계약을 위반한다.
**권장 조치**
별도 serializer를 만들지 않고 Community의 content 비교에서만 `trim()`을 제거한다. raw content 공백 변경이 저장되고 content 1개만 전송되는 component 회귀 test를 추가한다.
**판정 기록**
- 2026-08-06 — 확정. 기존 update 코드·schema가 raw content를 전송하고 현재 비교만 trim한다는 코드 근거로 판정했다.
- 2026-08-06 — 수정 완료. raw 비교 1줄과 공백 변경 회귀 test를 추가하고 focused·Phase Gate를 통과했다.
### REV-P1-002 — 완료된 Phase 1과 PRD 성공 기준 상태가 불일치함
- **심각도:** Low
- **상태:** 수정 완료
- **관련 요구사항:** PRD §14 성공 기준
- **관련 계약:** API Contract §4 검증 matrix
- **소유 Task:** `P1-GATE``P1-R2`
**관찰 내용**
`plan-task.md``P1-T1`~`P1-GATE`와 자동 검증을 완료로 기록했지만 `prd.md` §14의 기능·UI/UX·추적성 성공 기준은 모두 미완료 체크박스로 남아 있다.
**근거**
- 문서: `plan-task.md`의 완료 조건·Progress는 완료이고 `prd.md:217-235`는 미완료다.
- 테스트: Phase Gate 35 files / 228 tests, mock Chromium 39 tests, typecheck·lint·build가 통과했다.
- 규칙: 문서 유지보수와 리뷰 규칙은 완료 체크박스와 실제 증거의 일치를 요구한다.
**재현 또는 검증 절차**
1. `rg -n "^- \\[ \\]" docs/20260806_수정요청변경필드만전송/prd.md`를 실행한다.
2. 실제 결과: §14 성공 기준 13개가 미완료로 출력된다.
3. `plan-task.md`의 완료 조건과 `P1-GATE`, `P1-R1` Progress를 확인한다.
4. 요구 결과: 실행 증거가 있는 §14 항목은 완료이고, 요구사항 변경 시에만 쓰는 §18 체크리스트는 미완료 상태를 유지한다.
**영향**
구현 완료 여부를 PRD에서 판단할 수 없고 plan·review와 상태가 충돌한다. 실행 동작에는 영향이 없다.
**권장 조치**
새 검증이나 요구사항 변경 없이 기존 Gate 증거와 직접 연결되는 PRD §14 체크박스만 완료 표시한다.
**판정 기록**
- 2026-08-06 — 확정. 같은 working tree의 PRD와 plan 완료 상태가 직접 불일치한다.
- 2026-08-06 — 수정 완료. 기존 Gate 증거와 연결되는 PRD §14 항목 13개를 완료 표시하고 §18 체크리스트는 보존했다.
## 7. 확정 항목의 plan·goal 전환
### 신규 회귀 수정 Task 초안
`plan-task.md``Task R1.1 커뮤니티 content 직렬화 비교 일치`, `Task R1.2 PRD 성공 기준 상태 동기화`와 후속 goal을 반영했다.
- 실패 재현: raw content 공백 변경 시 저장 enabled와 `{content}` 전송 assertion
- 최소 수정: content 비교의 `trim()` 제거
- 검증: Community focused·전체와 Phase 1 Gate
- 범위 밖: content trim 정책 신설과 전용 mutation 변경
`P1-R2`는 기존 Gate 증거와 PRD §14를 대조해 검증된 성공 기준만 완료 표시한다. 요구사항·API Contract 의미와 §18 요구사항 변경 체크리스트는 바꾸지 않는다.
### create_goal objective 초안
```text
[P1-R1]의 확정 review 항목 REV-P1-001을 수정하고 회귀를 방지한다.
plan-task.md에 추가된 회귀 수정 Task만 수행한다.
실패 재현, 최소 수정, focused test, Phase Gate와 검증 기록이 모두 끝나기 전에는 complete로 표시하지 않는다.
관련 없는 리팩터링과 계약 추정은 범위 밖이다.
```
```text
[P1-R2]의 확정 review 항목 REV-P1-002를 수정해 PRD 성공 기준과 Phase 완료 증거를 동기화한다.
검증 증거가 없는 항목과 요구사항 변경 체크리스트는 완료 표시하지 않는다.
코드와 API Contract 의미 변경은 범위 밖이다.
```
## 8. 리뷰 종료 판정
| 판정 항목 | 결과 | 근거 |
|---|---|---|
| 리뷰 범위 전체 확인 | 충족 | 다섯 feature 코드·test와 세 기준 문서를 대조함 |
| 후보 항목 판정 완료 | 충족 | `REV-P1-001`, `REV-P1-002` 판정·수정 완료 |
| 확정 항목 plan 반영 | 충족 | `P1-R1`, `P1-R2` 추가·완료 |
| 보류 항목의 담당·재개 조건 기록 | 해당 없음 | 보류 항목 없음 |
| 검증 명령과 결과 기록 | 충족 | 35 files / 228 tests, mock Chromium 39 tests와 문서 정적 대조 결과 기록 |
**최종 결론:** 수정 검증 완료
**남은 항목:** 없음
## 9. 수정 후 검증 기록
기존 기록을 삭제하거나 덮어쓰지 않고 차수별로 누적한다.
### 1차 수정 검증 — 2026-08-06
- 무엇을: `REV-P1-001`의 Community raw content 비교 불일치를 수정하고 회귀 test를 추가했다.
- 왜: Community content의 비교와 전송 직렬화 불일치
- 어떻게:
- RED `npm run test:run -- src/features/community-posts/tests/community-sheet.test.tsx src/features/community-posts/tests/community-contract.test.ts` — exit 1, 1 failed / 26 passed. 공백 변경 후 저장 button disabled assertion 실패를 확인했다.
- GREEN 같은 focused 명령 — exit 0, 2 files / 27 tests 통과.
- `npm run test:run -- src/features/community-posts` — exit 0, 7 files / 52 tests 통과.
- `npm run test:run -- src/features/characters src/features/audio-contents src/features/community-posts src/features/series src/features/fan-talks` — exit 0, 35 files / 228 tests 통과.
- `npm run e2e:mock -- tests/e2e/character-workspace.spec.ts tests/e2e/audio-content.spec.ts tests/e2e/community.spec.ts tests/e2e/series.spec.ts tests/e2e/fan-talk.spec.ts --project=chromium` — sandbox에서는 local port bind `EPERM`; 승인된 동일 명령은 exit 0, 39 tests 통과.
- `npm run typecheck`; `npm run lint`; `npm run build` — 모두 exit 0.
- `git diff --check` — 출력 없음, exit 0.
- 실서버 Network는 인증 환경이 없어 불가했고 component multipart assertion과 mock E2E로 대체했다.
- 남은 항목: 없음
### 2차 수정 검증 — 2026-08-06
- 무엇을: `REV-P1-002`의 PRD §14 성공 기준 13개를 완료 증거와 동기화했다.
- 왜: PRD §14와 완료된 Phase 1 상태 불일치
- 어떻게:
- `rg -n "^- \\[x\\]" docs/20260806_수정요청변경필드만전송/prd.md` — §14 완료 항목 13개 확인, exit 0.
- `rg -n "^- \\[ \\]" docs/20260806_수정요청변경필드만전송/prd.md` — §18 요구사항 변경 체크리스트 5개만 유지, exit 0.
- 대상 PRD·API Contract·plan·review `test -f` — 누락 없음, exit 0.
- `git diff --check` — 출력 없음, exit 0.
- 남은 항목: 없음