Files

242 lines
15 KiB
Markdown

# 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 가용성은 자동 범위 밖이다.