Files

17 KiB

Phase 6 Community Posts 코드 리뷰·QA

1. 리뷰 정보

항목 내용
리뷰 대상 Phase 6 / Community 목록·생성·Sheet 수정·삭제
기준 commit 또는 working tree dd30e36323543e8f60e9983326503653e8001f12, 2026-07-31 종합 재점검 당시 사용자 변경을 포함한 current working tree
리뷰 일자 2026-07-31
리뷰어 Codex
기준 문서 prd.md, api-contract.openapi.json 2.3.0, plan-task.md
리뷰 상태 판정 완료, REV-P6-004 수정 완료 및 외부 수동 QA 대기

2. 리뷰 목적과 범위

목적

  • Community pagination, multipart mutation, mobile read-only capability와 Sheet 흐름을 검증한다.
  • 목록 상태 label이 운영자 표시 규칙과 일치하는지 확인한다.

포함 범위

  • 코드: src/features/community-posts
  • 테스트: Community contract/form/list/sheet/E2E
  • 문서: Community 요구사항, PRD §10·§13, P6-*
  • 수동 검증: desktop list의 상태 표시 정적 대조

제외 범위

  • Community Comments thread는 Phase 8에서 판정
  • 외부 서버의 media upload·audio playback

3. 판정 기준

심각도는 Blocker, High, Medium, Low, 상태는 후보, 확정, 오탐, 보류, 수정 완료를 사용한다. 기능·계약 위반을 우선하고 비핵심 표시 문자열은 Low로 판정한다.

4. 검토한 근거

문서와 코드

  • 요구사항: Community 요구사항과 PRD §13의 중앙 formatter 규칙
  • 계약: Community list/create/update/delete
  • 계획: P6-T1~P6-GATE
  • 코드: src/features/community-posts/components/CommunityPostList.tsx:22-30
  • 테스트: src/features/community-posts/tests/community-list.test.tsx:84-95

실행 환경

macOS 26.0 / Node v24.12.0 / npm 11.7.0
Playwright 4 projects, mobile read-only와 768/1280px 관리 흐름 포함

실행한 검증

명령 또는 수동 검증 결과 핵심 증거
npm run test:run 성공 72 files, 354 tests passed
npm run e2e:mock 부분 실패 Community 관련 실행 항목 통과 또는 프로젝트 정책상 skip; 전체 origin 실패는 REV-P0-004
npm run typecheck / npm run lint / npm run build 성공 모두 exit 0
Community list label 정적 대조 실패 성인 false/true 원시 boolean 노출, unit test가 문자열 고정

5. 발견 사항 요약

ID 심각도 상태 제목 소유 Task 후속 goal
REV-P6-002 Low 수정 완료 Community desktop 목록이 성인 여부를 false/true로 표시한다 P6-R2 P6-R2

6. 발견 사항 상세

REV-P6-002 — Community desktop 목록이 성인 여부를 false/true로 표시한다

  • 심각도: Low
  • 상태: 수정 완료
  • 관련 요구사항: PRD §13 표시 formatter 일관성
  • 관련 계약: Community list item의 isAdult boolean
  • 소유 Task: 신규 P6-R2

관찰 내용

desktop table의 플래그 열은 고정·댓글 여부는 한글 label로 변환하지만 성인 여부만 String(post.isAdult)로 출력한다. unit test도 “성인 false” 문구를 성공 조건으로 고정한다.

근거

  • 코드: src/features/community-posts/components/CommunityPostList.tsx:29
  • 테스트: src/features/community-posts/tests/community-list.test.tsx:93
  • 문서: prd.md:806

재현 또는 검증 절차

  1. Community 목록을 desktop 폭에서 연다.
  2. 일반 게시글의 상태 열에서 “성인 false”를 확인한다.
  3. 성인 콘텐츠에서는 “성인 true”가 표시됨을 코드로 확인한다.
  4. 요구 결과는 “일반 콘텐츠/성인 콘텐츠”처럼 운영자용 label을 표시하는 것이다.

영향

비핵심 플래그이지만 화면의 다른 한글 상태와 어긋나며 운영자가 내부 boolean을 해석해야 한다.

권장 조치

공통 boolean label 또는 Community formatter로 변환하고 unit/E2E assertion을 사용자 문구 기준으로 갱신한다.

판정 기록

  • 2026-07-30 — 구현과 현재 성공 test가 원시 boolean을 의도적으로 노출함을 확인해 확정.
  • 2026-07-30 — P6-R2에서 Community 전용 status label helper를 row/card에 적용하고 unit·mock E2E로 raw 성인 true/false 비노출을 확인해 수정 완료.

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

  • REV-P6-002plan-task.md 신규 P6-R2
  • goal objective: [P6-R2] Community 상태 boolean을 운영자용 label로 표시한다.

8. 리뷰 종료 판정

판정 항목 결과 근거
리뷰 범위 전체 확인 충족 Community code·test·계약 대조
후보 항목 판정 완료 충족 1건 수정 완료
확정 항목 plan 반영 충족 P6-R2
보류 항목의 담당·재개 조건 기록 해당 없음 보류 없음
검증 명령과 결과 기록 충족 §4, §9

최종 결론: 수정 검증 완료

남은 항목: REV-P6-002/P6-R2 범위 없음. P6-GATE server mode integration은 기존 외부 의존·server-mode 대상 spec 정합성 항목으로 별도 유지한다.

9. 수정 후 검증 기록

2026-07-30 — P6-R2 수정 검증

명령 또는 수동 검증 결과 핵심 증거
npm run test:run -- src/features/community-posts 성공 5 files, 42 tests passed. Unit test가 desktop/mobile status label 2건과 raw 성인 false 비노출을 검증한다.
npm run e2e:mock -- tests/e2e/community.spec.ts --project=chromium 성공 7 passed. Mobile card와 768/1280px desktop table에서 일반 콘텐츠/성인 콘텐츠 label 및 raw 성인 true/false 비노출을 검증한다.
npm run e2e:mock -- tests/e2e/community.spec.ts 성공 24 passed / 4 skipped. Skipped 항목은 기존 Chromium audio metadata 한정과 WebKit range input focus 제외 정책이다.
LSP diagnostics 성공 src/features/community-posts directory scan 10 files, 0 diagnostics. tests/e2e/community.spec.ts도 0 diagnostics.

판정: REV-P6-002는 수정 완료. API schema, request payload, mock mutation shape 변경은 없다.

10. 2차 점검 결과 — 2026-07-30

  • 전체 unit 72 files / 358 tests와 mock Chromium matrix 57 tests에서 Community 흐름이 통과했다.
  • Phase 6 신규 발견은 없으며 REV-P6-002 수정 완료 상태가 유지된다.

11. 2026-07-31 재점검

실행·판정 요약

  • 범위: Community 목록·Sheet·create/edit/fix/deactivate·media·Comments 결합을 PRD COMMUNITY-001~015, §10.4와 OpenAPI 2.3.0에 재대조했다.
  • 검증: 전체 unit 72 files / 360 tests, server allowlist 36 tests, typecheck·lint·build가 통과했다.
  • 신규 발견: Medium 1건. 기존 REV-P6-002는 수정 완료 상태를 유지한다.
ID 심각도 상태 제목 소유 Task 후속 goal
REV-P6-003 Medium 수정 완료 Community 게시글 비활성화가 확인 없이 즉시 실행된다 P6-R3 P6-R3

REV-P6-003 — Community 게시글 비활성화가 확인 없이 즉시 실행된다

  • 심각도: Medium
  • 상태: 수정 완료
  • 관련 요구사항: PRD §10.4, COMMUNITY-005
  • 관련 계약: Community post DELETE soft delete
  • 소유 Task: 신규 P6-R3

관찰 내용

Sheet의 비활성화 버튼은 deletePost를 직접 호출해 첫 click에 DELETE를 보낸다. Character·Audio·Series는 같은 영향의 동작에 ConfirmDeactivateDialog를 사용하지만 Community만 확인·영향 설명·취소 단계가 없다. 현재 unit/E2E도 첫 click 즉시 성공을 기대해 이 차이를 승인한다.

근거

  • 문서: prd.md:510-522 — 영향이 큰 비활성화는 AlertDialog 사용
  • 코드: src/features/community-posts/components/CommunityPostSheet.tsx:110-122,170-174
  • 테스트: src/features/community-posts/tests/community-sheet.test.tsx:68-73, tests/e2e/community.spec.ts:155

재현 또는 검증 절차

  1. active Community 게시글 Sheet를 연다.
  2. 비활성화를 한 번 누른다.
  3. 확인 dialog 없이 즉시 DELETE와 Sheet close가 실행되는지 확인한다.

영향

오조작 한 번으로 게시글이 active-only 목록에서 사라지며 현재 UI에는 복원 기능이 없다. 동일한 soft delete 정책의 다른 도메인과 안전 경계도 불일치한다.

권장 수정 방향

기존 공통 ConfirmDeactivateDialog를 재사용해 영향 설명·취소·confirm·pending/error를 연결하고, 확인 전·취소 후 request 0건과 confirm 연타 1건을 test로 고정한다.

판정 기록:

  • 2026-07-31 — PRD UI 원칙과 도메인별 deactivate 구현을 대조해 확정.
  • 2026-07-31 — P6-R3에서 공통 ConfirmDeactivateDialog를 연결하고, 첫 click·취소 후 request 0건과 confirm 연타 시 단일 soft delete를 unit test로 고정해 수정 완료.

plan·goal 전환 및 종료 판정

  • REV-P6-003plan-task.md 신규 P6-R3
  • 최종 결론: 신규 Medium 1건 수정 완료. Blocker/High 없음.
  • 공통 UI: Community/Comments 화면의 pagination ID 충돌은 REV-P1-015/P1-R9이 소유한다.

2026-07-31 — P6-R3 수정 검증

명령 또는 수동 검증 결과 핵심 증거
npm run test:run -- src/features/community-posts/tests/community-sheet.test.tsx 성공 1 file, 7 tests passed. 첫 click 확인 dialog, 취소 focus 복귀, confirm 연타 단일 soft delete를 검증한다.
npm run test:run -- src/features/community-posts 성공 5 files, 42 tests passed. Community feature 회귀가 통과했다.
npm run typecheck / npm run lint / npm run build 성공 모두 exit 0. Production build는 기존 chunk size warning만 출력했다.
git diff --check 성공 whitespace error 없음.
LSP diagnostics 성공 src/features/community-posts directory scan 10 files, 0 diagnostics.

판정: REV-P6-003는 수정 완료. E2E는 개발 중 매 Task 실행하지 않는 사용자 지시에 따라 전체 Task 완료 후 필요 시 수행한다.

12. 최종 Phase별 점검 — 2026-07-31

  • 검토 범위: Community 목록·create/update/fixed/deactivate, attachment file 정책, list-backed Sheet, 댓글 연결을 COMMUNITY-*, OpenAPI, P6와 대조했다.
  • 실행 증거: npm run test:run -- src/features/community-posts 5 files / 42 tests, mock Chromium Community 시나리오 7 tests가 통과했다.
  • 판정: Community payload·file 정책의 별도 신규 finding은 없다. create/update/fixed mutation의 동기 재진입 guard와 진행 표시 공백은 교차 품질 finding REV-P9-006/P9-R6에 귀속했다.
  • 남은 위험: 실제 개발 API Community 수동 QA와 P9-R6 완료가 필요하다.
  • 신규 Phase 6 Task: 없음. 중복 Task 대신 P9-R6에서 추적한다.

13. 종합 재점검 — 2026-07-31

  • 검토 범위: Community pagination·create/update/fixed/deactivate·attachment/crop 정책·Sheet·Comments 연결을 재대조했다.
  • 실행 증거: Community를 포함한 도메인 묶음 36 files / 206 tests, exact server E2E 18/18, 현재 두 project mock E2E 109 passed / 5 skipped가 통과했다.
  • 판정: Community endpoint·multipart payload·Sheet 소유의 확정 신규 finding은 없다.
  • 교차 Phase: JPEG/PNG crop 문제는 REV-P1-016~017, 댓글 POST 실패의 초안 소실은 REV-P8-005에서 공통 수정한다.
  • 남은 위험: 실제 개발 API Community mutation 수동 QA가 남아 있다. WebKit 계열 Gate는 현재 지원 범위에서 제외한다.
  • 신규 Phase 6 Task: 없음.

14. 요청 기준 재리뷰 — 2026-07-31

  • 검토 범위: Community pagination, create/update/fixed/deactivate, JPEG/PNG/GIF·audio attachment, Sheet와 Comments 연결.
  • 실행 증거: 관련 unit과 4-project mock Community journey·responsive·axe가 0 failure였고 OpenAPI pagination/multipart schema ref 점검도 통과했다.
  • 판정: Phase 6 소유의 확정 신규 발견 사항 없음.
  • 남은 위험: 실제 개발 API Community mutation·active-only·media reject 수동 QA.
  • 신규 Phase 6 Task: 없음.

15. 최종 재검증 — 2026-07-31

  • 검토 범위: Community pagination, create/update/fixed/deactivate, media·crop policy, Sheet와 Comments 연결.
  • 실행 증거: 전체 unit 394 tests와 4-project mock Community·responsive·axe 시나리오가 0 failure였고 OpenAPI pagination/multipart schema ref 검사도 통과했다.
  • 판정: Phase 6 소유의 확정 신규 발견 사항 없음.
  • 남은 위험: 실제 개발 API Community mutation·active-only·media reject 수동 QA.
  • 신규 Phase 6 Task: 없음.

16. 2026-07-31 문서 기준 재리뷰

검토 범위와 제외

  • 검토: PRD COMMUNITY-*, FILE-001~015, OpenAPI Community list/multipart operation, create/Sheet media lifecycle, GIF/JPEG/PNG 정책과 test를 current working tree에서 대조했다.
  • 제외: 실제 server의 GIF width·MIME 거부와 memory profiler를 이용한 장시간 사용 계측은 credential·실기기 수동 QA로 남겼다.

REV-P6-004 GIF dimension 검사용 Blob URL 미해제

항목 내용
심각도 Medium
상태 수정 완료
관련 요구사항 FILE-003, FILE-011, FILE-014
소유 Task P6-R4

근거

  • src/features/community-posts/validation/community-post-media-policy.ts:60에서 createCropSource(file)로 preview Blob URL과 release를 소유한 source를 만든다.
  • 같은 파일 :61-64의 GIF 분기는 width가 800px 이하이면 ready, 초과면 error를 반환하면서 source.release?.()를 호출하지 않고 source도 반환하지 않는다.
  • CommunityPostForm.tsx:51,66-69CommunityPostSheet.tsx:34,63-66의 cleanup은 prepared.kind === "crop"인 JPEG/PNG source만 인수받는다. GIF에서 손실된 release를 호출할 수 없다.
  • 현재 Community test는 valid/oversized GIF의 선택·제출 결과는 검증하지만 release 호출 횟수를 직접 검증하지 않는다.

재현·영향

  1. valid GIF 또는 800px 초과 GIF를 선택할 때마다 createImageCropSource()가 만든 object URL이 해제되지 않는다.
  2. 게시물 작성·수정에서 대용량 GIF를 반복 교체하면 tab의 memory 사용량이 불필요하게 유지될 수 있다. 저장 file 변조·animation 손실은 확인되지 않았다.

권장 조치·판정 기록

  • GIF width 판정 직후 ready/거부 반환 전에 source를 해제하고, valid·oversized GIF에 release 각 1회, JPEG/PNG crop handoff에 조기 release 0회를 검증한다.
  • 2026-07-31 — source 소유권 data flow를 정적 추적해 Medium 확정. 완료된 P1-R11을 열지 않고 Community GIF 특수 분기 소유의 신규 P6-R4로 전환했다. 제품 코드는 수정하지 않았다.
  • 2026-07-31 — P6-R4에서 prepareCommunityPostImage() GIF width 판정 후 source release를 호출하도록 수정했다. RED 1 failure 재현 후 media policy·form·Sheet focused 3 files / 18 tests, Community 회귀 7 files / 45 tests, typecheck, lint, 개발/운영 build가 통과했고 reviewer blocker였던 release 순서도 width → release test로 보강해 delta review APPROVED를 받았다. E2E와 반복 GIF 수동 확인은 전체 Task 구현 후 필요 시 수행한다.

재리뷰 검증·종료 판정

  • 자동 증거: npm run typecheck, npm run lint, 개발/운영 build, server E2E 36 tests는 통과했다. 전체 unit은 79 files / 397 tests 중 5 failed / 392 passed였고, Community Sheet를 포함한 후보 5개 spec focused는 5 files / 25 tests passed였다. 비결정성은 REV-P9-009/P9-R9로 분리했다.
  • 판정: Medium 1건을 확정해 P6-R4로 전환했고 수정 완료했다. 오탐·보류로 남은 후보는 없다.
  • 남은 위험: 실제 개발 API media reject·active-only mutation QA와 반복 GIF 선택 memory 계측은 P6-R4·수동 QA 완료 전까지 남는다.

17. 수정 결과 재리뷰 — 2026-07-31

  • 검토: prepareCommunityPostImage()의 valid/oversized GIF release와 JPEG/PNG crop source handoff를 구현·test에서 재대조했다.
  • 검증: npm run test:run -- src/features/community-posts/tests/community-post-media-policy.test.ts src/features/community-posts/tests/community-form.test.tsx src/features/community-posts/tests/community-sheet.test.tsx — exit 0, 3 files / 18 tests passed. 전체 unit도 두 차례 연속 81 files / 409 tests passed했고 typecheck·lint·개발/운영 build가 통과했다. Community를 포함한 Chromium 4-spec focused mock E2E도 31 tests passed였다.
  • 판정: REV-P6-004 수정은 유지됐다. Phase 6 소유의 추가 확정 발견 사항은 없다.
  • 남은 위험: 실제 개발 API media reject·active-only mutation QA와 장시간 반복 선택 memory 계측은 수동 범위다.