# Phase 0 프로젝트 기반 코드 리뷰·QA ## 1. 리뷰 정보 | 항목 | 내용 | |---|---| | 리뷰 대상 | Phase 0 / 프로젝트 기반, 환경 설정, 기본 Gate | | 기준 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` | | 리뷰 상태 | 판정 완료, 회귀 수정 완료 | ## 2. 리뷰 목적과 범위 ### 목적 - Phase 0의 환경별 API origin, 실행 명령, 기본 품질 Gate가 현재 구현과 일치하는지 확인한다. - 완료 기록과 현재 working tree의 코드·테스트·문서가 같은 기준을 사용하는지 검증한다. ### 포함 범위 - 코드·설정: `.env*`, `src/shared/config`, Vite·Vitest·Playwright 설정 - 테스트: 전체 unit, mock/server Playwright Gate, typecheck, lint, build - 문서: PRD 공통 API 원칙, `P0-*`, README와 환경 가이드 - 수동 검증: 환경 파일과 실제 요청 intercept origin 정적 대조 ### 제외 범위 - 외부 개발 API에 대한 실제 ADMIN 계정 로그인과 운영 데이터 검증 - 발견 사항의 코드·테스트 수정 ## 3. 판정 기준 | 심각도 | 기준 | |---|---| | Blocker | 보안·데이터 손실 위험, 핵심 흐름 불능, 완료 판정을 무효화하는 문제 | | High | 확정 요구사항·API Contract 위반 또는 주요 회귀 | | Medium | 제한된 조건의 기능·접근성·복구 문제 | | Low | 비핵심 UX 또는 문서 정합성 문제 | 상태는 `후보`, `확정`, `오탐`, `보류`, `수정 완료`를 사용한다. ## 4. 검토한 근거 ### 문서와 코드 - 요구사항: PRD §4, §6, §13, §14 - 계획: `P0-T1`~`P0-GATE` - 설정: `.env.development:1`, `.env.production:1` - 문서: `README.md:21-22`, `docs/agent-guide/environment.md:3-4` - 테스트: `tests/e2e/auth.spec.ts:3`, `accessibility-shell.spec.ts:4`, `server-mode-boundary.spec.ts:4`, `error-mapping.spec.ts:12`, `comments-test-support.ts:3` ### 실행 환경 ```text OS: macOS 26.0 (Build 25A354) Node: v24.12.0 npm: 11.7.0 Browser: Playwright Chromium, Mobile Chrome 환경 변수: VITE_API_MODE=mock/server, VITE_API_BASE_URL(값은 저장소 공개 설정만 대조) ``` ### 실행한 검증 | 명령 또는 수동 검증 | 결과 | 핵심 증거 | |---|---|---| | `npm run typecheck` | 성공 | exit 0 | | `npm run lint` | 성공 | exit 0 | | `npm run test:run` | 성공 | 72 files, 354 tests passed | | `npm run build` | 성공 | exit 0, 253 modules transformed | | `npm run e2e:mock` | 실패 | 201 passed, 22 skipped, 5 failed; 4개 프로젝트의 error-mapping이 과거 origin으로 요청해 500 수신 | | `npm run e2e:mock -- tests/e2e/series.spec.ts --project=webkit --grep "desktop and tablet Series management flow remains available at 768px"` | 성공 | 1 passed; 전체 실행의 단일 timeout은 재현되지 않음 | | `npm run e2e` | 실패 | 12 passed, 24 failed; auth·shell·server boundary가 현재 앱 origin을 intercept하지 못함 | | `jq` operation/status 집계 및 component schema `$ref` 차집합 검증 | 성공 | 두 명령 모두 exit 0; 25 paths, 37 operations, status 전부 `implemented`, 누락 schema ref 없음 | OpenAPI 검증은 다음 명령으로 실행했다. ```bash jq '[.paths[] | to_entries[] | select(.key | IN("get", "put", "post", "delete", "patch", "head", "options", "trace")) | .value] as $operations | {openapi, version: .info.version, paths: (.paths | length), operations: ($operations | length), statuses: ([$operations[]."x-implementation-status"] | unique)}' docs/20260725_AI캐릭터관리자웹/api-contract.openapi.json jq -e '((([.. | objects | .["$ref"]? // empty | select(startswith("#/components/schemas/")) | split("/")[-1]] | unique) - (.components.schemas | keys)) | length) == 0' docs/20260725_AI캐릭터관리자웹/api-contract.openapi.json ``` ## 5. 발견 사항 요약 | ID | 심각도 | 상태 | 제목 | 소유 Task | 후속 goal | |---|---|---|---|---|---| | `REV-P0-004` | High | 수정 완료 | API origin 변경이 문서와 Playwright route에 반영되지 않아 브라우저 Gate가 실패한다 | `P0-R2` | `P0-R2` | ## 6. 발견 사항 상세 ### REV-P0-004 — API origin 변경이 문서와 Playwright route에 반영되지 않아 브라우저 Gate가 실패한다 - **심각도:** High - **상태:** 수정 완료 - **관련 요구사항:** PRD §4, §6.2, §13, §14 - **관련 계약:** 모든 OpenAPI operation의 server-mode 요청 경계 - **소유 Task:** 신규 `P0-R2` **관찰 내용** 현재 개발·운영 환경 파일은 각각 `https://test-api.sodalive.net`, `https://api.sodalive.net`을 사용한다. README, 환경 가이드와 다섯 Playwright 지원 파일은 과거 `test-character-admin`/`character-admin` origin을 사용한다. 앱 요청과 테스트 route가 서로 다른 origin을 바라보므로 mock 오류 매핑과 server auth·shell·retry 검증이 실제 요청을 가로채지 못한다. **근거** - 코드: `.env.development:1`, `.env.production:1` - 테스트: `tests/e2e/auth.spec.ts:3`, `accessibility-shell.spec.ts:4`, `server-mode-boundary.spec.ts:4`, `error-mapping.spec.ts:12`, `comments-test-support.ts:3` - 문서: `README.md:21-22`, `docs/agent-guide/environment.md:3-4` - 자동화: mock Gate 4개 동일 error-mapping 실패, server Gate 24개 실패 **재현 또는 검증 절차** 1. 현재 `.env.development`를 유지한다. 2. `npm run e2e:mock`을 실행한다. 3. 과거 origin 요청이 MSW handler와 일치하지 않아 기대한 401 대신 500이 반환되는 것을 확인한다. 4. `npm run e2e`를 실행해 로그인·shell·server retry route가 현재 요청을 intercept해야 하지만 24개 test가 실패하는 것을 확인한다. **영향** 브라우저 Gate가 제품 회귀와 무관하게 실패하고, server-mode 인증·오류 경계 및 Comments 연동을 올바른 origin에서 검증하지 못한다. README를 따르는 개발자도 잘못된 서버 주소를 사용하게 된다. **권장 조치** 공개 환경 파일을 단일 기준으로 README·환경 가이드·Playwright route/probe를 동기화하고, 과거 host 검색과 mock/server focused test를 회귀 증거로 추가한다. **판정 기록** - 2026-07-30 — 설정·문서·테스트 문자열 대조와 두 브라우저 Gate의 반복 실패로 확정. - 2026-07-30 — `P0-R2`에서 E2E API origin helper와 문서 현재값을 정렬하고 focused/full Gate 분할 검증으로 수정 완료 판정. ## 7. 확정 항목의 plan·goal 전환 - `REV-P0-004` → `plan-task.md` 신규 `P0-R2` - goal objective: `[P0-R2] API origin 단일 기준을 문서와 모든 Playwright route/probe에 동기화하고 mock/server Gate 회귀를 방지한다.` ## 8. 리뷰 종료 판정 | 판정 항목 | 결과 | 근거 | |---|---|---| | 리뷰 범위 전체 확인 | 충족 | 설정·문서·정적·자동 Gate 확인 | | 후보 항목 판정 완료 | 충족 | 1건 확정 | | 확정 항목 plan 반영 | 충족 | `P0-R2` 완료 | | 보류 항목의 담당·재개 조건 기록 | 해당 없음 | 보류 없음 | | 검증 명령과 결과 기록 | 충족 | §4에 실제 결과 기록 | **최종 결론:** 확정 발견 사항 수정 완료. **남은 항목:** 없음. ## 9. 수정 후 검증 기록 - 2026-07-30 — `P0-R2` RED: `npm run e2e:mock -- tests/e2e/error-mapping.spec.ts`는 4 failed / 4 passed로 과거 origin unhandled 500을 재현했고, `npm run e2e -- tests/e2e/server-mode-boundary.spec.ts --project=chromium`은 2 failed / 2 passed로 stale route/probe 실패를 재현했다. - 2026-07-30 — `tests/e2e/api-base-url.ts`를 추가해 E2E route/probe가 `.env.development`의 `VITE_API_BASE_URL`을 읽게 하고, README와 환경 가이드를 `https://test-api.sodalive.net` / `https://api.sodalive.net`로 정렬했다. - 2026-07-30 — GREEN focused: `npm run e2e:mock -- tests/e2e/error-mapping.spec.ts` 8 passed, `npm run e2e -- tests/e2e/server-mode-boundary.spec.ts --project=chromium` 4 passed, `npm run e2e -- tests/e2e/comments.spec.ts --project=chromium` 3 passed. - 2026-07-30 — Gate: `npm run e2e` 36 passed. `npm run e2e:mock` 단일 실행은 900초 제한으로 188/228 진행 중 timeout됐으나, 같은 allowlist를 project별로 분할해 `chromium` 57 passed, `webkit` 49 passed / 8 skipped, `mobile-chrome` 52 passed / 5 skipped, `mobile-safari` 48 passed / 9 skipped로 전체 mock matrix를 확인했다. - 2026-07-30 — 정적 검증: `rg -n 'test-character-admin|character-admin\.sodalive\.net' README.md docs/agent-guide tests/e2e` no matches, `npm run typecheck`, `npm run lint`, `npm run build` 모두 exit 0, `tests/e2e` LSP diagnostics 오류 0건. ## 10. 2차 점검 결과 — 2026-07-30 - `npm ci`, `npm run typecheck`, `npm run lint`, `npm run build`가 모두 exit 0이었다. - 전체 unit은 72 files / 358 tests, server allowlist E2E는 36 tests, mock Chromium matrix는 57 tests가 통과했다. - Phase 0 신규 발견은 없으며 `REV-P0-004` 수정 완료 상태가 유지된다. ## 11. 2026-07-31 재점검 - **기준:** commit `dd30e36323543e8f60e9983326503653e8001f12`, 재점검 시작 시 working tree 변경 220개. 기존 사용자 변경은 수정하지 않고 현재 tree를 검토했다. - **검증:** `npm run typecheck`, `npm run lint`, `npm run build`는 exit 0, `npm run test:run`은 72 files / 360 tests passed, `npm run e2e`는 36 passed였다. - **계약·구성 판정:** package scripts, 환경 mode 경계, build와 server allowlist에서 Phase 0 신규 결함은 확인되지 않았다. `REV-P0-004`는 수정 완료 상태를 유지한다. - **교차 Phase:** 당시 Mobile Safari 간헐 실패 후보는 이후 지원 project 축소로 현재 Task에서 제외했다. - **신규 Task:** 없음. ## 12. 최종 Phase별 점검 — 2026-07-31 - **검토 범위:** package scripts, TypeScript·ESLint·production build, server/mock mode 실행 경계, 현재 Playwright project 구성을 `P0` Gate와 재대조했다. - **실행 증거:** `npm run typecheck`, `npm run lint`, `npm run build` exit 0. server E2E는 샌드박스의 최초 `listen EPERM`을 제품 실패와 분리한 뒤 승인된 로컬 실행에서 18/18 통과했다. - **판정:** 현재 지원 project인 Chromium·Mobile Chrome 기준 기반 설정과 server allowlist에서 확정 신규 발견 사항 없음. - **남은 위험:** 실제 개발 API의 가용성·운영 배포 환경은 이 Phase 자동 검증 범위 밖이다. - **신규 Task:** 없음. ## 13. 종합 재점검 — 2026-07-31 ### `REV-P0-005` — 문서 디렉터리의 `.DS_Store`가 version control index에 포함됨 | 항목 | 내용 | |---|---| | 심각도 | Low | | 상태 | 수정 완료 | | 관련 요구사항·계약 | Phase 0 재현 가능한 프로젝트 기반과 저장소 문서 유지보수; API 계약 영향 없음 | | 소유 Task | `P0-R3` | | 근거 | `git ls-files 'docs/20260725_AI캐릭터관리자웹/.DS_Store'`가 해당 binary entry를 반환하고 `.gitignore`에는 `.DS_Store` 규칙이 없다. | **재현 또는 검증 절차** 1. `git ls-files | rg '(^|/)\.DS_Store$'`를 실행한다. 2. `docs/20260725_AI캐릭터관리자웹/.DS_Store`가 출력되는지 확인한다. 3. `rg -n '^\.DS_Store$' .gitignore`가 no matches인지 확인한다. **영향과 권장 조치** 운영체제별 binary metadata가 문서 변경에 섞여 불필요한 diff와 충돌을 만들 수 있다. 해당 entry만 제거하고 저장소 전역 ignore 규칙을 추가한다. 다른 사용자 파일이나 문서 내용은 정리하지 않는다. **판정 기록** - 2026-07-31 — 현재 index와 ignore 규칙을 정적으로 대조해 확정. - 2026-07-31 — 애플리케이션 코드는 수정하지 않고 `plan-task.md` 신규 `P0-R3`로 전환. - 2026-07-31 — `P0-R3`에서 `.DS_Store`를 index와 working tree에서 제거하고 저장소 ignore 규칙을 추가해 수정 완료 판정. ### Phase 0 결론 - **자동 검증:** `npm run typecheck`, `npm run lint`, `npm run build:dev`, `npm run build:prod` 모두 exit 0. 두 build는 기존 500kB 초과 chunk warning만 출력했다. - **판정:** runtime·환경 mode·script의 신규 결함은 없다. Low 1건은 `P0-R3`에서 수정 완료됐다. - **남은 위험:** 실제 배포 환경과 개발 API 가용성은 자동 검증 범위 밖이다. ### P0-R3 수정 후 검증 — 2026-07-31 - 무엇을: 문서 디렉터리의 `.DS_Store` staged entry를 제거하고 저장소 ignore 규칙을 추가했다. - 왜: 운영체제별 binary metadata가 문서 변경과 충돌에 섞이지 않게 하기 위해서다. - 검증: `git ls-files | rg '(^|/)\.DS_Store$'`와 `git status --short --untracked-files=all | rg '\.DS_Store'`는 no matches, `rg -n '^\.DS_Store$' .gitignore`는 `7:.DS_Store`, `git diff --check -- .gitignore docs/20260725_AI캐릭터관리자웹`은 exit 0이었다. ## 14. 요청 기준 재리뷰 — 2026-07-31 - **기준:** commit `dd30e36323543e8f60e9983326503653e8001f12`와 사용자 변경을 포함한 current working tree. - **검증:** `typecheck`, `lint`, `build:dev`, `build:prod` exit 0, server-mode Chromium·WebKit·Mobile Chrome·Mobile Safari smoke/auth/boundary 36 passed. 두 build는 기존 500kB 초과 chunk warning만 표시했다. - **판정:** Phase 0 runtime·환경·build 소유의 신규 기능 결함은 없다. 전체 unit 실패는 `P9-R7`의 mock E2E script 문서·test 정합성으로 `REV-P9-008`에 귀속한다. - **문서 교차 항목:** 상단 리뷰 상태가 완료된 `P0-R3`와 어긋나는 문제는 `REV-P10-008`/`P10-R7`에서 과거 기록을 보존한 채 정리한다. - **신규 Phase 0 Task:** 없음. ## 15. 최종 재검증 — 2026-07-31 - **검토 범위:** package script, server/mock mode, 환경 변수, 개발·운영 build와 browser project 구성을 다시 확인했다. - **실행 증거:** `npm run test:run` 78 files / 394 tests, `npm run e2e` 36 tests, `npm run e2e:mock` 186 passed / 22 skipped가 통과했다. `typecheck`, `lint`, `build:dev`, `build:prod`, staged/unstaged diff check도 exit 0이었다. - **판정:** Phase 0 소유의 확정 신규 발견 사항 없음. build의 502.94kB chunk warning은 PRD·plan에 hard limit가 없어 이번 Task로 전환하지 않는다. - **남은 위험:** 실제 배포 환경과 개발 API 가용성은 자동 검증 범위 밖이다. - **신규 Phase 0 Task:** 없음. ## 16. 2026-07-31 문서 기준 재리뷰 - **검토 범위:** `package.json`, Vite/Vitest/Playwright 설정, server/mock 명령, 환경 mode 경계, build 산출물과 `P0`·`P9` Gate 기록을 PRD·plan에 대조했다. - **실행 증거:** `npm run typecheck`, `npm run lint`, `npm run build:dev`, `npm run build:prod` exit 0, server E2E 4 projects / 36 passed. build는 기존 503.04kB chunk warning만 표시했다. 전체 unit은 79 files / 397 tests 중 5 failed / 392 passed였고, 기반 코드가 아닌 integration harness 비결정성 `REV-P9-009`/`P9-R9`로 분리했다. - **판정:** Phase 0 runtime·실행 스크립트·환경 mode 소유의 확정 신규 발견 사항 없음. 후보·오탐·보류 0건, 신규 Phase 0 Task 없음. - **남은 위험:** 503.04kB warning은 문서 hard limit가 없어 Task로 전환하지 않았다. 실제 배포 환경과 개발 API 가용성은 자동 범위 밖이다.