Files

11 KiB

Phase 4 코드 리뷰·QA — 2026-07-29

1. 리뷰 정보

항목 내용
리뷰 대상 Phase 4 / Audio vertical slice
기준 commit 또는 working tree dd30e36323543e8f60e9983326503653e8001f12; 리뷰 시작 시 tracked diff 36개, 전체 변경 169개
리뷰 일자 2026-07-29
리뷰어 Codex
기준 문서 prd.md, api-contract.openapi.json, plan-task.md
리뷰 상태 판정 완료

2. 리뷰 목적과 범위

목적

  • AUDIO-001~033, upload·price·media/file 기준과 Phase 4/P10 후속 결과를 대조한다.

포함 범위

  • 코드: src/features/audio-contents
  • 테스트: Audio contract/form/upload/player
  • 문서: Audio 요구사항·OpenAPI request·Phase 4 Task/Gate
  • 수동 검증: form control과 upload lifecycle 정적 대조

제외 범위

  • 공통 crop 계산은 Phase 1, inactive workspace와 공통 field 접근성은 Phase 9, 공통 오류 문구 최종 회귀는 Phase 10

3. 판정 기준

심각도는 Blocker/High/Medium/Low, 상태는 확정/오탐/보류/수정 완료를 사용했다.

4. 검토한 근거

문서와 코드

  • 요구사항: AUDIO-014, AUDIO-017~019, AUDIO-024, AUDIO-033, AUTH-005, FILE-002
  • 코드: AudioContentForm.tsx:60, AudioContentForm.tsx:103, AudioContentForm.tsx:171, AudioContentForm.tsx:179, audio-content-form-helpers.ts:11, audio-content-form-helpers.ts:12, audio-content-form-helpers.ts:87, upload-audio-content.ts:51, upload-audio-content.ts:61, upload-audio-content.ts:85
  • 테스트: audio-form.test.tsx, audio-form-upload.test.tsx, audio-upload.test.ts, audio-contract.test.ts

실행 환경

OS: macOS 26.0
Node: v24.12.0
npm: 11.7.0
API mode: injected upload client/XHR fake/MSW

실행한 검증

명령 또는 검증 결과 핵심 증거
npm run test:run -- src/features/audio-contents src/features/series 성공 합계 11 files / 46 tests passed
가격 parser node 계산 실패 재현 -1 → 1, 1.5 → 15
form/upload code 대조 실패 재현 optional control 누락, upload 중 submit 활성, XHR 401 session 처리 없음

5. 발견 사항 요약

ID 심각도 상태 제목 소유 Task 후속 goal
REV-P4-001 High 수정 완료 Audio create form이 OpenAPI optional 설정을 고정값으로만 보낸다 P4-T3 P4-R1
REV-P4-002 High 수정 완료 음수·소수 가격을 거부하지 않고 다른 유효값으로 바꾼다 P10-T7 P4-R1
REV-P4-003 High 수정 완료 upload 중 중복 submit이 가능하다 P4-T3 P4-R2
REV-P4-004 High 수정 완료 XHR upload 401이 session clear/login 이동을 실행하지 않는다 P4-T3 P4-R2
REV-P4-005 Medium 수정 완료 .m4a + audio/mp4가 file picker accept에서 누락됐다 P4-T3 P4-R3
REV-P4-006 Medium 수정 완료 cover image의 확장자와 MIME 불일치가 통과한다 P4-T3 P4-R3

6. 발견 사항 상세

REV-P4-001 — Audio create form이 확정 optional 설정을 제공하지 않는다

  • 심각도: High
  • 상태: 수정 완료
  • 관련 요구사항: AUDIO-033
  • 관련 계약: AudioContentCreateRequest
  • 소유 Task: 신규 P4-R1

관찰 내용

purchaseOption, limited, isAdult, isGeneratePreview, isOnlyRental, isPointAvailable, isCommentAvailable, isFullDetailVisible, previewStartTime, previewEndTime, languageCode를 편집하는 control이 없다. serializer는 전부 고정 default로 보낸다.

영향

운영자가 OpenAPI와 PRD에 확정된 발행·구매·댓글·미리보기 설정을 선택할 수 없다.

권장 조치

계약 enum/type만 사용한 최소 control을 추가하고 create payload·dirty state·접근성 test를 보강한다.

판정 기록

  • 2026-07-29 — visible control과 serializer 고정값을 대조해 확정.
  • 2026-07-30 — create 전용 optional 설정 control과 serializer를 추가하고 Audio unit/mock E2E/static/build 검증 통과.

REV-P4-002 — Audio 가격의 금지 입력이 다른 값으로 변환된다

  • 심각도: High
  • 상태: 수정 완료
  • 관련 요구사항: AUDIO-019, PRD 14.1 가격 경계
  • 관련 계약: price integer 0..99999
  • 소유 Task: 신규 P4-R1

관찰 내용

parser가 숫자가 아닌 모든 문자를 제거한다. -11캔, 1.515캔이 되어 validation을 통과한다.

영향

사용자가 거부돼야 할 값을 입력했는데 의도와 다른 가격이 저장될 수 있다.

권장 조치

허용 display suffix/group separator만 정규화하고 부호·소수점은 invalid raw state로 유지해 제출을 차단한다. -1, 1.5 form test를 추가한다.

판정 기록

  • 2026-07-29 — parser 계산으로 확정.
  • 2026-07-30 — -1, 1.5, 100000 raw 입력을 변형하지 않고 request 0건으로 차단하도록 수정하고 Audio unit/mock E2E/static/build 검증 통과.

REV-P4-003 — Audio upload 중 중복 제출이 차단되지 않는다

  • 심각도: High
  • 상태: 수정 완료
  • 관련 요구사항: Character/Audio form 저장 중 중복 제출, AUDIO-017
  • 관련 계약: Audio create POST
  • 소유 Task: 신규 P4-R2

관찰 내용

submit handler에 uploading guard가 없고 생성 버튼도 uploadState.status로 비활성화되지 않는다. 첫 요청 pending 중 다시 submit하면 새 AbortController와 POST를 시작한다.

영향

중복 콘텐츠 생성·대용량 중복 전송이 발생할 수 있다.

권장 조치

synchronous ref guard와 disabled 상태를 함께 적용하고 pending upload double-submit test를 추가한다.

판정 기록

  • 2026-07-29 — submit/button 경로에 guard 0건으로 확정.
  • 2026-07-30 — synchronous pending ref와 uploading disabled button을 추가해 pending 중 submit 2회를 request 1건으로 차단하고 cancel 후 재제출 가능함을 focused test로 확인.

REV-P4-004 — XHR upload 401에서 인증 상태가 남는다

  • 심각도: High
  • 상태: 수정 완료
  • 관련 요구사항: AUTH-005
  • 관련 계약: upload 보호 요청 401
  • 소유 Task: 신규 P4-R2

관찰 내용

XHR adapter는 storage에서 token만 읽고 401을 일반 ApiError로 reject한다. 공통 client의 clearSession/onAuthExpired 경로를 사용하지 않는다.

영향

대용량 upload 도중 session이 만료되면 login으로 복구되지 않는다.

권장 조치

공통 인증 만료 callback을 upload adapter에 주입하거나 동일한 단일 session expiry controller를 사용하고 XHR 401 test를 추가한다.

판정 기록

  • 2026-07-29 — XHR adapter의 session remove·redirect 호출 0건으로 확정.
  • 2026-07-30 — upload adapter에 token reader/session clear/login callback을 주입하고 protected 401 burst에서 clear/login 1회만 실행하도록 수정. malformed 401과 normal 401 회귀 test 및 공통 client-auth 회귀 통과.

REV-P4-005 — canonical M4A MIME이 file picker에서 빠졌다

  • 심각도: Medium
  • 상태: 수정 완료
  • 관련 요구사항: AUDIO-014, AUDIO-024
  • 관련 계약: .m4a + audio/mp4
  • 소유 Task: 신규 P4-R3

관찰 내용

validator는 audio/mp4를 허용하지만 input acceptaudio/mpeg,audio/aac,audio/x-m4a만 제공한다.

영향

브라우저 file chooser가 정상 M4A 파일을 숨기거나 선택을 방해할 수 있다.

권장 조치

AUDIO_FILE_POLICY.allowedMimeTypes를 accept source로 재사용해 중복을 제거한다.

판정 기록

  • 2026-07-29 — validator와 input accept 대조로 확정.
  • 2026-07-30 — Audio file picker accept를 AUDIO_FILE_POLICY.allowedMimeTypes.join(",")로 변경해 audio/mp4 포함을 focused test로 확인.

REV-P4-006 — Audio cover format pair가 검증되지 않는다

  • 심각도: Medium
  • 상태: 수정 완료
  • 관련 요구사항: FILE-002
  • 관련 계약: JPEG/PNG cover
  • 소유 Task: 신규 P4-R3

관찰 내용

.png + image/jpeg, .jpg + image/png가 extension allowlist와 MIME allowlist를 각각 통과한다.

영향

잘못된 multipart가 backend까지 전송된다.

권장 조치

extension별 MIME map과 mismatch test를 추가한다.

판정 기록

  • 2026-07-29 — validateAudioCoverFile이 공통 독립 allowlist만 호출함을 확인해 확정.
  • 2026-07-30 — cover extension별 MIME pair 검증을 추가해 .jpg/.jpeg + image/png, .png + image/jpegmime 오류로 차단하고 contract 회귀 test로 확인.

7. 확정 항목의 plan·goal 전환

  • REV-P4-001~002P4-R1
  • REV-P4-003~004P4-R2
  • REV-P4-005~006P4-R3

8. 리뷰 종료 판정

판정 항목 결과 근거
리뷰 범위 전체 확인 충족 Audio contract/form/upload/file 대조
후보 항목 판정 완료 충족 6건 확정
확정 항목 plan 반영 충족 P4-R1~R3
보류 항목 담당·재개 조건 해당 없음 보류 없음
검증 명령과 결과 기록 충족 §4

최종 결론: 수정 goal 필요.

남은 항목: P4-R1~R3, Phase 9 inactive/접근성, Phase 10 오류 회귀.

9. 수정 후 검증 기록

  • 2026-07-30 — P4-R1 완료. 검증: npm run test:run -- src/features/audio-contents 8 files / 35 tests passed, npm run e2e:mock -- tests/e2e/audio-content.spec.ts 21 passed / 3 skipped, npm run typecheck, npm run lint, npm run build, targeted git diff --check 통과.
  • 2026-07-30 — P4-R2 완료. RED: audio-form-upload.test.tsx는 pending upload 중 2회 호출로 실패했고, audio-upload.test.ts는 protected 401에서 clearSession 0회로 실패했다. GREEN/검증: npm run test:run -- src/features/audio-contents/tests/audio-form-upload.test.tsx 1 file / 6 tests passed, npm run test:run -- src/features/audio-contents/tests/audio-upload.test.ts src/shared/api/__tests__/client-auth.test.ts 2 files / 19 tests passed, npm run test:run -- src/features/audio-contents 8 files / 38 tests passed, npm run typecheck, npm run lint, npm run build, targeted git diff --check 통과.
  • 2026-07-30 — P4-R3 완료. RED: audio-form-upload.test.tsx는 accept audio/mp4 누락으로 실패했고, audio-contract.test.ts는 cover mismatch가 { ok: true }로 실패했다. GREEN/검증: npm run test:run -- src/features/audio-contents/tests/audio-form-upload.test.tsx 1 file / 7 tests passed, npm run test:run -- src/features/audio-contents/tests/audio-contract.test.ts src/shared/validation/file-media-policy.test.ts 2 files / 17 tests passed, npm run test:run -- src/features/audio-contents src/features/community-posts 12 files / 76 tests passed, npm run typecheck, npm run lint, npm run build, targeted git diff --check 통과.