9.9 KiB
Phase 1 코드 리뷰·QA — 2026-07-29
1. 리뷰 정보
| 항목 | 내용 |
|---|---|
| 리뷰 대상 | Phase 1 / 공통 API·인증·file/crop 기반 |
| 기준 commit 또는 working tree | dd30e36323543e8f60e9983326503653e8001f12; 리뷰 시작 시 tracked diff 36개, 전체 변경 169개 |
| 리뷰 일자 | 2026-07-29 |
| 리뷰어 | Codex |
| 기준 문서 | prd.md, api-contract.openapi.json, plan-task.md |
| 리뷰 상태 | 판정 완료 |
2. 리뷰 목적과 범위
목적
AUTH-001~013,FILE-001~015, 공통 API envelope와 crop 계약을 현재 구현과 대조한다.- 기존
review-phase-0-1.md에서 수정 완료된 항목은 보존하고 새 회귀만 판정한다.
포함 범위
- 코드:
src/shared/api,src/shared/lib/crop-image.ts,src/shared/ui/image-crop-dialog.tsx, 인증 저장소 - 테스트: 공통 API 인증·오류, crop 계산·Dialog
- 문서: Phase 1 Task·Gate와 PRD 인증/file 기준
- 수동 검증: 코드 계산과 keyboard/pointer control 정적 대조
제외 범위
- resource별 form과 multipart serializer, 실제 모바일 pinch 기기 QA
3. 판정 기준
| 심각도 | 기준 |
|---|---|
| Blocker | 보안·데이터 손실 또는 핵심 흐름 불능 |
| High | 확정 요구사항·계약 위반 또는 주요 회귀 |
| Medium | 제한 조건의 기능·접근성·복구 문제 |
| Low | 비핵심 UX·문서 정합성 |
상태는 확정/오탐/보류/수정 완료를 사용했다.
4. 검토한 근거
문서와 코드
- 요구사항:
AUTH-005,FILE-012, PRD10.4 - 코드:
src/shared/api/client.ts:92,src/shared/api/client.ts:102,src/shared/api/client.ts:122,src/shared/lib/crop-image.ts:67,src/shared/lib/crop-image.ts:69,src/shared/ui/image-crop-dialog.tsx:38,src/shared/ui/image-crop-dialog.tsx:154 - 테스트:
src/shared/api/__tests__/client-auth.test.ts,src/shared/lib/crop-image.test.ts,src/shared/ui/__tests__/image-crop-dialog.test.tsx
실행 환경
OS: macOS 26.0
Node: v24.12.0
npm: 11.7.0
API mode: unit stub/MSW
실행한 검증
| 명령 또는 검증 | 결과 | 핵심 증거 |
|---|---|---|
npm run test:run -- src/shared/lib/crop-image.test.ts src/shared/ui/__tests__/image-crop-dialog.test.tsx src/shared/api/__tests__/client-auth.test.ts src/shared/api/__tests__/client.test.ts |
성공 | 4 files / 27 tests passed |
node crop 계산 |
실패 재현 | 600px 원본, zoom 1.5에서 source crop 400px, output 600px, 1.5배 확대 |
| 코드 경로 대조 | 실패 재현 | 401 처리가 정상 오류 envelope parse 뒤에만 존재 |
5. 발견 사항 요약
| ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal |
|---|---|---|---|---|---|
REV-P1-011 |
High | 수정 완료 | 비정상 envelope·JSON인 401은 session을 제거하지 않는다 | P1-T2 |
P1-R6 |
REV-P1-012 |
High | 수정 완료 | zoom crop이 선택 영역보다 큰 결과를 만들어 no-upscale을 위반한다 | P1-T5 |
P1-R7 |
REV-P1-013 |
Medium | 수정 완료 | crop Dialog에 pinch/zoom 입력이 없다 | P1-T5 |
P1-R7 |
6. 발견 사항 상세
REV-P1-011 — 비정상 401에서 인증 만료 처리가 누락된다
- 심각도: High
- 상태: 수정 완료
- 관련 요구사항:
AUTH-005 - 관련 계약: 보호 요청의 HTTP 401
- 소유 Task: 신규
P1-R6
관찰 내용
response.json() 실패와 envelope schema 실패는 즉시 공통 ApiError를 던진다. session clear와 login 이동은 정상 오류 envelope가 parse된 뒤의 !apiResponse.success 분기에서만 실행된다.
재현 또는 검증 절차
- 인증이 필요한 요청에 session을 저장한다.
- server가 body 없는 401, non-JSON 401 또는 malformed envelope 401을 반환하게 한다.
- 현재 결과는 status 401 오류만 발생하고 session clear/redirect callback은 0회다.
- 요구 결과는 body 형태와 무관하게 보호 요청 401에서 1회 session clear와 login 이동이다.
영향
만료·무효 token이 브라우저 session에 남고 사용자가 보호 화면에서 반복 실패할 수 있다.
권장 조치
응답 body parse 전에 HTTP status 기반 인증 만료를 공통 처리하되 동시 401 burst 1회 규칙을 유지하고 malformed/empty 401 회귀 test를 추가한다.
판정 기록
- 2026-07-29 — 코드의 모든 401 경로를 대조해 확정.
- 2026-07-30 —
P1-R6에서 HTTP status 기반 인증 만료 처리를 body parse 전에 수행하도록 수정하고 malformed JSON, empty body, schema mismatch 401 회귀를 추가해 수정 완료로 판정.
REV-P1-012 — zoom crop 결과가 선택 원본 영역을 확대한다
- 심각도: High
- 상태: 수정 완료
- 관련 요구사항:
FILE-012 - 관련 계약: resource별
noUpscale=true - 소유 Task: 신규
P1-R7
관찰 내용
출력 크기는 항상 zoom=1인 crop 영역으로 계산하지만 실제 source 영역은 현재 zoom으로 축소된다. 600×600 원본을 1.5배 확대하면 source는 400×400인데 output은 600×600이다.
재현 또는 검증 절차
- 600×600 이미지와 1:1, maxWidth 800, noUpscale 정책을 연다.
- zoom을 1.5로 바꾸고 적용한다.
calculateCropSourceRect는 400×400, Dialog는 output 600×600을 전달한다.- 요구 결과는 output이 선택 source crop의 pixel 크기를 넘지 않는 것이다.
영향
Character·Audio·Series·Community JPEG/PNG crop이 확대되어 품질이 저하되고 파일 계약을 위반한다.
권장 조치
output size 계산에 현재 zoom의 source rect를 사용하고 zoom 경계별 실제 canvas draw test를 추가한다.
판정 기록
- 2026-07-29 — 계산 결과
scale=1.5로 확정. - 2026-07-30 —
P1-R7에서CropOutputSizeRequest.zoom을 반영해 zoom 1.5의 600×600 source crop output을 400×400으로 제한했고, focused/broad Vitest와 typecheck로 수정 완료 판정.
REV-P1-013 — crop Dialog가 pinch/zoom을 지원하지 않는다
- 심각도: Medium
- 상태: 수정 완료
- 관련 요구사항: PRD
10.4 - 관련 계약: 없음
- 소유 Task: 신규
P1-R7
관찰 내용
range, 버튼/keyboard zoom과 단일 pointer drag는 있으나 두 pointer 거리 또는 gesture를 처리하는 pinch 입력 경로가 없다.
영향
tablet/mobile touch 사용자가 명시된 pinch/zoom 방식으로 crop을 조작할 수 없다.
권장 조치
기존 range/keyboard 대안을 유지한 채 두 pointer pinch를 최소 구현하고 pointer 회귀 test와 실제 touch QA 항목을 추가한다.
판정 기록
- 2026-07-29 — pointer handler와 테스트 전체 검색에서 pinch 경로 0건으로 확정.
- 2026-07-30 —
P1-R7에서 native pointer map/ref 기반 two-pointer pinch zoom을 추가하고 pointerup/pointercancel/pointerleave cleanup을 연결했다. Dialog 회귀 test로 pinch zoom 1.5, 기존 drag/range/keyboard 경로를 확인해 수정 완료 판정.
7. 확정 항목의 plan·goal 전환
REV-P1-011→P1-R6REV-P1-012~013→P1-R7
8. 리뷰 종료 판정
| 판정 항목 | 결과 | 근거 |
|---|---|---|
| 리뷰 범위 전체 확인 | 충족 | API 401·crop code/test 대조 |
| 후보 항목 판정 완료 | 충족 | 3건 모두 확정 |
| 확정 항목 plan 반영 | 충족 | P1-R6, P1-R7 |
| 보류 항목 담당·재개 조건 | 해당 없음 | 보류 없음 |
| 검증 명령과 결과 기록 | 충족 | §4 |
최종 결론: 확정 항목 수정 완료.
남은 항목: 없음.
9. 수정 후 검증 기록
- 2026-07-30
P1-R6— REDnpm run test:run -- src/shared/api/__tests__/client-auth.test.ts src/shared/api/__tests__/client.test.ts에서 malformed JSON, empty body, schema mismatch 401이clearSession0회로 3건 실패했다. GREEN 같은 command는 2 files / 21 tests passed. LSP diagnostics는src/shared/api/client.ts,src/shared/api/__tests__/client-auth.test.ts모두 오류 0건이었다. Auth/session focused regressionnpm run test:run -- src/features/auth/tests/auth-session.test.tsx src/features/auth/tests/login-page.test.tsx src/app/App.test.tsx src/app/App.protected-auth.test.tsx는 3 files / 24 tests passed. Broadnpm run test:run -- src/features/auth src/app은REV-P10-001/P10-R1의 stale fallback assertion 6건으로 실패해 기존 Phase 10 후속 범위로 유지한다. - 2026-07-30
P1-R7— REDnpm run test:run -- src/shared/lib/crop-image.test.ts src/shared/ui/__tests__/image-crop-dialog.test.tsx에서 zoom 1.5 output 600×600과 pinch 미지원으로 2 failed / 9 passed를 확인했다. 1차 review blocker 보강 RED는 210:297 zoom 1.8 output 236×334의 source height 1px 초과와touch-action: none누락으로 2 failed / 11 passed였고, tiny source 0×0 붕괴 RED는npm run test:run -- src/shared/lib/crop-image.test.ts1 failed / 6 passed였다. 2차 review blocker 보강 RED는 aspect 2 tiny source 1×0 붕괴로npm run test:run -- src/shared/lib/crop-image.test.ts1 failed / 6 passed였다. 3차 review blocker 보강 RED는 free aspect tiny source 1×2 output이 source height를 초과해npm run test:run -- src/shared/lib/crop-image.test.ts2 failed / 5 passed였다. GREEN focused는 2 files / 14 tests passed로 zoom 1.5 output 400×400, 210:297 zoom 1.8 output 236×333, tiny source 1×1, aspect 2 tiny source 1×1, free aspect tiny source 1×1, two-pointer pinch zoom 1.5와 previewtouch-action: none을 확인했다. Broad crop regression은 23 files / 119 tests passed였다. Surface E2Enpm run e2e:mock -- tests/e2e/series.spec.ts --project=chromium은 7 tests passed로 실제 브라우저의 Series 생성 crop Dialog open/apply 경로를 확인했다.npm run typecheck,npm run lint는 exit 0이고,src/shared/ui,tests/e2eLSP diagnostics는 오류 0건이었다. 실제 tablet touch 장비 QA는 수행하지 못해 릴리스 QA 항목으로 유지한다.