- 오디오 media error는 signed URL 만료로 구분하거나 추정하지 않는다. 재생 오류만으로 목록·상세 API를 자동 재조회하거나 `play()`를 자동 재호출하지 않으며 일반 오류와 수동 재시도·페이지 새로고침 안내를 제공한다.
- 오디오 media error는 signed URL 만료로 구분하거나 추정하지 않는다. 재생 오류만으로 목록·상세 API를 자동 재조회하거나 `play()`를 자동 재호출하지 않으며 일반 오류와 수동 재시도·페이지 새로고침 안내를 제공한다.
- 커뮤니티 첨부 audio URL만을 갱신하기 위한 요청은 하지 않고 media error를 refetch trigger로 사용하지 않는다. 사용자 페이지 새로고침이나 mutation 후 cache 무효화 등 일반 목록 재조회에서는 새 응답의 URL을 사용한다. 전용 상세 조회나 URL 재발급 호출을 추가하지 않는다.
- 커뮤니티 첨부 audio URL만을 갱신하기 위한 요청은 하지 않고 media error를 refetch trigger로 사용하지 않는다. 사용자 페이지 새로고침이나 mutation 후 cache 무효화 등 일반 목록 재조회에서는 새 응답의 URL을 사용한다. 전용 상세 조회나 URL 재발급 호출을 추가하지 않는다.
### 1.5 개발 전용 Mock Preview 계약 경계
- browser MSW handler와 fixture는 이 문서에 **제공됨**으로 기록된 endpoint, request/response DTO와 오류 규칙에서만 파생한다.
- mock mode도 production과 같은 URL, method, header, serializer, envelope와 API client를 사용하며 별도 mock 전용 DTO·adapter를 만들지 않는다.
- 계약은 제공됐지만 backend endpoint가 아직 404인 경우 mock mode에서 최종 UI를 확인할 수 있다. server mode의 404·network error를 감지해 mock으로 자동 fallback하지 않는다.
- “백엔드 제공 대기” 항목은 fixture로 추정하지 않는다. 계약이 제공되기 전에는 관련 최종 network UI와 integration 완료를 주장하지 않는다.
- mock mutation은 deterministic in-memory store를 갱신하고 새로고침 때 seed로 초기화한다. domain fixture를 browser 영구 저장소에 기록하지 않는다.
- mock mode는 개발 환경에서만 명시적으로 활성화하고 production build에서는 거부한다.
- mock UI Gate 통과는 실제 backend 연동 완료 증거가 아니다. 각 도메인은 `UI 확인 완료(mock)`와 `실제 서버 연동 완료(server)` 결과를 별도로 기록한다.
- [ ] handler와 fixture가 `src/shared/test/server.ts`의 Node test lifecycle을 변경하지 않고 필요한 contract factory만 공유하게 한다.
### Task 2.3 Mock Preview 반응형·문서화
**Goal 실행 `P2-T3`:** mock mode의 browser 접근성·반응형과 실행 문서를 검증해 사용자가 최종 UI 확인 mode를 명확히 선택하게 한다.
- **시작 조건:** `P2-T1`, `P2-T2` 완료.
- **완료 증거:** 320px·desktop mock shell E2E, axe 결과, README와 environment/scripts 가이드의 실제 명령 동기화 기록.
- **범위 밖:** 도메인별 최종 UI와 server integration 완료 주장.
- [ ] mock banner가 320px·200% zoom에서 핵심 control을 가리지 않고 axe critical·serious 위반이 없는지 E2E로 확인한다.
- [ ] README에 `npm run dev`와 `npm run dev:mock`, mode 차이, mock data reset, production 금지와 no-auto-fallback을 기록한다.
- [ ] 구현이 완료된 뒤 `docs/agent-guide/environment.md`와 `scripts.md`에 실제 환경 변수와 명령을 추가한다.
- [ ] 후속 도메인 Phase가 handler·fixture·mock E2E를 소유한다는 규칙을 문서화한다.
### Phase 2 Gate
**Goal 실행 `P2-GATE`:** mock/server mode 경계, auth preview와 production 차단을 최종 판정한다.
- **시작 조건:** `P2-T1`~`P2-T3` 완료.
- **완료 증거:** 아래 명령과 Expected 통과 및 Phase 2 Progress 기록.
- **범위 밖:** mock 성공을 실제 도메인 server integration 성공으로 간주하는 것.
```bash
npm run test:run -- src/shared/config src/shared/mocks src/shared/ui/__tests__/mock-mode-banner.test.tsx
npm run e2e:mock -- tests/e2e/mock-preview-shell.spec.ts
npm run typecheck
npm run lint
npm run build:dev
npm run build:prod
```
**Expected:**`npm run dev:mock`에서는 ADMIN login → protected shell과 mock banner가 동작하고 실제 backend 요청은 0건이다. 기본 server mode는 실제 API 오류를 그대로 처리하며 production build는 browser mock을 활성화하지 않는다.
---
## Phase 3. Character workspace vertical slice
**목표:** ADMIN이 active Character를 검색·생성·선택하고 workspace에서 상세·수정·soft delete까지 완료한다.
**목표:** ADMIN이 active Character를 검색·생성·선택하고 workspace에서 상세·수정·soft delete까지 완료한다.
- [ ] 제공 계약 범위의 Character seed, loading·empty·error·success와 CRUD/deactivate browser handler 시나리오를 확정한다. 계약 미제공 original work network fixture는 만들지 않는다.
### Task 2.2 목록·선택·workspace
### Task 3.2 목록·선택·workspace
**Goal 실행 `P2-T2`:** active Character 목록·검색·선택과 URL 기반 workspace 복원을 완성한다.
**Goal 실행 `P3-T2`:** active Character 목록·검색·선택과 URL 기반 workspace 복원을 완성한다.
- **시작 조건:** `P2-T1` 완료.
- **시작 조건:** `P3-T1` 완료.
- **완료 증거:** 체크박스 전체, route/list/workspace test와 read-only/error 상태 검증 기록.
- **완료 증거:** 체크박스 전체, route/list/workspace test와 read-only/error 상태 검증 기록.
- **범위 밖:** Character 생성·수정·비활성화 form.
- **범위 밖:** Character 생성·수정·비활성화 form.
@@ -625,12 +722,13 @@ npm run build
- [ ] workspace header에 image, name, active 상태, `characterId`와 탭·breadcrumb를 표시한다.
- [ ] workspace header에 image, name, active 상태, `characterId`와 탭·breadcrumb를 표시한다.
- [ ] 상세 성공 응답이 `isActive=false`이면 read-only 배너와 중앙 write policy로 모든 mutation 진입점을 차단한다.
- [ ] 상세 성공 응답이 `isActive=false`이면 read-only 배너와 중앙 write policy로 모든 mutation 진입점을 차단한다.
- [ ] 상세 400/404/500은 공통 오류 화면을 사용하고 비활성 ID 응답 정책을 client가 추정하지 않는다.
- [ ] 상세 400/404/500은 공통 오류 화면을 사용하고 비활성 ID 응답 정책을 client가 추정하지 않는다.
- [ ] browser MSW handler와 deterministic seed로 목록 → 선택 → workspace deep link의 최종 UI를 `dev:mock`에서 확인한다.
### Task 2.3 생성·수정·soft delete
### Task 3.3 생성·수정·soft delete
**Goal 실행 `P2-T3`:** Character multipart 생성·수정·soft delete와 image/original-work 규칙을 완성한다.
**Goal 실행 `P3-T3`:** Character multipart 생성·수정·soft delete와 image/original-work 규칙을 완성한다.
**Goal 실행 `P2-GATE`:** Character 전체 journey와 공통 품질 Gate를 최종 판정한다.
**Goal 실행 `P3-GATE`:** Character mock UI journey와 실제 server integration 상태를 분리해 판정한다.
- **시작 조건:** `P2-T1`~`P2-T4` 완료.
- **시작 조건:** `P3-T1`~`P3-T4` 완료.
- **완료 증거:** 아래 명령과 Expected 통과, 외부 의존의 구현/제외 상태 기록.
- **완료 증거:** 아래 명령과 Expected 통과, 외부 의존의 구현/제외 상태 기록.
- **범위 밖:** 실패와 무관한 Audio 기능.
- **범위 밖:** 실패와 무관한 Audio 기능.
```bash
```bash
npm run test:run -- src/features/characters src/layouts/CharacterWorkspaceLayout.test.tsx
npm run test:run -- src/features/characters src/layouts/CharacterWorkspaceLayout.test.tsx
npm run e2e:mock -- tests/e2e/character-workspace.spec.ts
npm run e2e -- tests/e2e/character-workspace.spec.ts
npm run e2e -- tests/e2e/character-workspace.spec.ts
npm run typecheck
npm run typecheck
npm run lint
npm run lint
npm run build
npm run build
```
```
**Expected:** login → Character 검색/생성 → 선택/workspace → 수정 → soft delete → active-only 목록 복귀가 한 slice로 통과한다. original work 계약이 없으면 그 기능의 제외 결정과 문서가 명시돼야 하며 완료로 가장하지 않는다.
**Expected:** mock mode에서 login → Character 검색/생성 → 선택/workspace → 수정 → soft delete → active-only 목록 복귀의 최종 UI가 통과한다. server mode 결과는 별도로 기록하며 backend 미구현 404이면 `UI 확인 완료(mock) / 실제 서버 연동 대기`로 남긴다. original work 계약이 없으면 fixture를 추정하지 않는다.
---
---
## Phase 3. Audio vertical slice
## Phase 4. Audio vertical slice
**목표:** 선택 Character의 Audio를 검색·검수·발행·수정·비활성화하고 대용량 upload를 안전하게 제어한다.
**목표:** 선택 Character의 Audio를 검색·검수·발행·수정·비활성화하고 대용량 upload를 안전하게 제어한다.
**Goal 실행 `P3-GATE`:** Audio journey, upload 복구와 media 오류 불변식을 최종 판정한다.
**Goal 실행 `P4-GATE`:** Audio mock UI journey와 실제 server integration 상태를 분리해 판정한다.
- **시작 조건:** `P3-T1`~`P3-T4` 완료.
- **시작 조건:** `P4-T1`~`P4-T4` 완료.
- **완료 증거:** 아래 명령과 Expected 통과 및 Phase 검증 기록.
- **완료 증거:** 아래 명령과 Expected 통과 및 Phase 검증 기록.
- **범위 밖:** 실패와 무관한 Series/Community 구현.
- **범위 밖:** 실패와 무관한 Series/Community 구현.
```bash
```bash
npm run test:run -- src/features/audio-contents src/shared/ui src/shared/validation
npm run test:run -- src/features/audio-contents src/shared/ui src/shared/validation
npm run e2e:mock -- tests/e2e/audio-content.spec.ts
npm run e2e -- tests/e2e/audio-content.spec.ts
npm run e2e -- tests/e2e/audio-content.spec.ts
npm run typecheck
npm run typecheck
npm run lint
npm run lint
npm run build
npm run build
```
```
**Expected:** Audio 즉시/예약 생성 → 진행률/취소/재시도 → 목록·상세 재생 → 수정 → soft delete가 통과하고 media error가 자동 refetch·자동 재생을 0회 발생시킨다.
**Expected:** mock mode에서 Audio 즉시/예약 생성 → 진행률/취소/재시도 → 목록·상세 재생 → 수정 → soft delete의 최종 UI가 통과하고 media error가 자동 refetch·자동 재생을 0회 발생시킨다. server mode는 별도 결과를 기록한다.
---
---
## Phase 4. Series vertical slice
## Phase 5. Series vertical slice
**목표:** 선택 Character의 Series를 생성·수정·비활성화하고 Audio 연결·해제와 활성 Series 전체 순서를 관리한다.
**목표:** 선택 Character의 Series를 생성·수정·비활성화하고 Audio 연결·해제와 활성 Series 전체 순서를 관리한다.
- [ ] 제공 계약 범위만 Series CRUD·연결·순서 browser fixture로 만들고 genre·후보·충돌 계약 미제공 부분은 mock에서도 추정하지 않는다.
### Task 4.2 Series CRUD
### Task 5.2 Series CRUD
**Goal 실행 `P4-T2`:** Series CRUD, enum·요일·image와 soft delete 규칙을 완성한다.
**Goal 실행 `P5-T2`:** Series CRUD, enum·요일·image와 soft delete 규칙을 완성한다.
- **시작 조건:** `P4-T1` 완료.
- **시작 조건:** `P5-T1` 완료.
- **완료 증거:** 체크박스 전체, contract/form/image/list/detail/deactivate test와 검증 기록.
- **완료 증거:** 체크박스 전체, contract/form/image/list/detail/deactivate test와 검증 기록.
- **범위 밖:** Audio 연결·해제와 전체 순서 저장.
- **범위 밖:** Audio 연결·해제와 전체 순서 저장.
@@ -852,12 +957,13 @@ npm run build
- [ ] genre 계약이 제공됐다면 이름 검색 후 `genreId`만 전송하는 Combobox를 test한다.
- [ ] genre 계약이 제공됐다면 이름 검색 후 `genreId`만 전송하는 Combobox를 test한다.
- [ ] Series image JPEG/PNG·10MB, `210:297`, `height=round(width×297÷210)`, 최대 1000×1414, 1px 오차, no-upscale을 test한다.
- [ ] Series image JPEG/PNG·10MB, `210:297`, `height=round(width×297÷210)`, 최대 1000×1414, 1px 오차, no-upscale을 test한다.
- [ ] 일반 update와 soft delete의 `isActive` 규칙, soft delete 후 목록 이동·toast를 test한다.
- [ ] 일반 update와 soft delete의 `isActive` 규칙, soft delete 후 목록 이동·toast를 test한다.
- [ ] mock store로 Series CRUD 후 list/detail과 server state enum이 일관되게 갱신되는 최종 UI를 확인한다.
### Task 4.3 Audio 연결·해제·전체 순서
### Task 5.3 Audio 연결·해제·전체 순서
**Goal 실행 `P4-T3`:** Series Audio 연결·해제와 active Series 전체 순서를 안전하게 관리한다.
**Goal 실행 `P5-T3`:** Series Audio 연결·해제와 active Series 전체 순서를 안전하게 관리한다.
- **시작 조건:** `P4-T1`, `P4-T2` 완료 및 관련 P0 계약 제공.
- **시작 조건:** `P5-T1`, `P5-T2` 완료 및 관련 P0 계약 제공.
- **완료 증거:** 체크박스 전체, link/unlink/reorder contract·interaction test, 충돌 보존, `OQ-009` 결정 기록.
- **완료 증거:** 체크박스 전체, link/unlink/reorder contract·interaction test, 충돌 보존, `OQ-009` 결정 기록.
- **범위 밖:** 계약 없는 후보/전체 로딩/충돌 동작의 추정 구현.
- **범위 밖:** 계약 없는 후보/전체 로딩/충돌 동작의 추정 구현.
@@ -869,12 +975,13 @@ npm run build
- [ ] drag-and-drop과 동일한 결과를 keyboard·위/아래 button으로 만들 수 있는 test를 작성한다.
- [ ] drag-and-drop과 동일한 결과를 keyboard·위/아래 button으로 만들 수 있는 test를 작성한다.
- [ ] server의 누락 ID·동시 충돌 오류에서 기존 화면 순서를 보존하고 재조회/재시도 안내를 제공한다.
- [ ] server의 누락 ID·동시 충돌 오류에서 기존 화면 순서를 보존하고 재조회/재시도 안내를 제공한다.
- [ ] Series form·연결·순서 UI를 실제로 작성한 뒤 `OQ-009`의 title·introduction·keywords·writer·studio·days·contentIds·seriesIds 상한 필요성을 판단하고, 구현 전 결정 문서를 갱신하거나 “상한 추가 없음”으로 종결한다.
- [ ] Series form·연결·순서 UI를 실제로 작성한 뒤 `OQ-009`의 title·introduction·keywords·writer·studio·days·contentIds·seriesIds 상한 필요성을 판단하고, 구현 전 결정 문서를 갱신하거나 “상한 추가 없음”으로 종결한다.
- [ ] 계약 제공 후 mock handler가 연결·해제와 전체 순서 payload를 검증하고 store 결과를 반영하는 E2E를 작성한다.
### Task 4.4 Series 반응형·접근성
### Task 5.4 Series 반응형·접근성
**Goal 실행 `P4-T4`:** Series viewport capability와 form·연결·정렬 접근성을 검증한다.
**Goal 실행 `P5-T4`:** Series viewport capability와 form·연결·정렬 접근성을 검증한다.
- **시작 조건:** `P4-T2`, `P4-T3`의 활성 범위 완료.
- **시작 조건:** `P5-T2`, `P5-T3`의 활성 범위 완료.
- **완료 증거:** 체크박스 전체, 320px·keyboard·200% zoom·axe E2E 기록.
- **완료 증거:** 체크박스 전체, 320px·keyboard·200% zoom·axe E2E 기록.
**Goal 실행 `P4-GATE`:** Series CRUD·연결·전체 reorder journey와 serializer 불변식을 판정한다.
**Goal 실행 `P5-GATE`:** Series mock UI journey와 실제 server integration 상태를 분리해 판정한다.
- **시작 조건:** `P4-T1`~`P4-T4` 완료.
- **시작 조건:** `P5-T1`~`P5-T4` 완료.
- **완료 증거:** 아래 명령과 Expected 통과, 외부 의존 상태와 Phase 검증 기록.
- **완료 증거:** 아래 명령과 Expected 통과, 외부 의존 상태와 Phase 검증 기록.
- **범위 밖:** 실패와 무관한 Community/FanTalk 구현.
- **범위 밖:** 실패와 무관한 Community/FanTalk 구현.
```bash
```bash
npm run test:run -- src/features/series
npm run test:run -- src/features/series
npm run e2e:mock -- tests/e2e/series.spec.ts
npm run e2e -- tests/e2e/series.spec.ts
npm run e2e -- tests/e2e/series.spec.ts
npm run typecheck
npm run typecheck
npm run lint
npm run lint
npm run build
npm run build
```
```
**Expected:** Series 생성 → 수정 → Audio 연결/해제 → active 전체 reorder → soft delete가 통과하고 잘못된 enum·부분 순서 payload가 생성되지 않는다.
**Expected:** 제공 계약 범위의 mock mode에서 Series 생성 → 수정 → Audio 연결/해제 → active 전체 reorder → soft delete 최종 UI가 통과하고 잘못된 enum·부분 순서 payload가 생성되지 않는다. server mode는 별도 결과를 기록한다.
---
---
## Phase 5. Community vertical slice
## Phase 6. Community vertical slice
**목표:** 별도 상세 route/GET 없이 active Community 목록과 Sheet만으로 게시글 등록·조회·수정·고정·비활성화·첨부 재생을 완료한다.
**목표:** 별도 상세 route/GET 없이 active Community 목록과 Sheet만으로 게시글 등록·조회·수정·고정·비활성화·첨부 재생을 완료한다.
**Phase Goal `P5`:** Task 5.1 → 5.4와 Phase 5 Gate로 목록 기반 Community Sheet·media slice를 완성한다.
**Phase Goal `P6`:** Task 6.1 → 6.4와 Phase 6 Gate로 목록 기반 Community Sheet·media slice를 완성한다.
- **시작 조건:** `P1-T6` file/media primitive와 `P3-T2` player integration 완료.
- **시작 조건:** `P2-GATE`와 `P4-T2` player integration 완료.
- **완료 조건:** `P5-T1`~`P5-T4`, `P5-GATE` 완료. 오류·price는 제공 계약 또는 최소 규칙으로 종결.
- **완료 조건:** `P6-T1`~`P6-T4`, `P6-GATE` 완료. 오류·price는 제공 계약 또는 최소 규칙으로 종결.
- **실행 순서:** 계약 확인 → 목록/Sheet → form/media → 반응형·접근성.
- **실행 순서:** 계약 확인 → 목록/Sheet → form/media → 반응형·접근성.
**요구사항:**`COMMUNITY-001~011`, `FILE-001~004`, `FILE-007~009`, `FILE-011~014`, PRD `9`의 Community 범위.
**요구사항:**`COMMUNITY-001~011`, `FILE-001~004`, `FILE-007~009`, `FILE-011~014`, PRD `9`의 Community 범위.
**외부 의존:** Community 신규 오류 계약, optional P1 price 상한. Comments는 Phase 7에서 연결한다.
**외부 의존:** Community 신규 오류 계약, optional P1 price 상한. Comments는 Phase 8에서 연결한다.
**Goal 실행 `P5-GATE`:** Community 목록/Sheet CRUD·pin·media journey와 no-detail 불변식을 판정한다.
**Goal 실행 `P6-GATE`:** Community mock UI journey와 실제 server integration 상태를 분리해 판정한다.
- **시작 조건:** `P5-T1`~`P5-T4` 완료.
- **시작 조건:** `P6-T1`~`P6-T4` 완료.
- **완료 증거:** 아래 명령과 Expected 통과 및 Phase 검증 기록.
- **완료 증거:** 아래 명령과 Expected 통과 및 Phase 검증 기록.
- **범위 밖:** 실패와 무관한 FanTalk/Comments 구현.
- **범위 밖:** 실패와 무관한 FanTalk/Comments 구현.
```bash
```bash
npm run test:run -- src/features/community-posts src/shared/validation
npm run test:run -- src/features/community-posts src/shared/validation
npm run e2e:mock -- tests/e2e/community-post.spec.ts
npm run e2e -- tests/e2e/community-post.spec.ts
npm run e2e -- tests/e2e/community-post.spec.ts
npm run typecheck
npm run typecheck
npm run lint
npm run lint
npm run build
npm run build
```
```
**Expected:** create → 목록 item Sheet 조회/수정 → pin/unpin → 첨부 재생 → soft delete가 통과하고 Community detail GET·detail route 호출은 0건이다.
**Expected:** mock mode에서 create → 목록 item Sheet 조회/수정 → pin/unpin → 첨부 재생 → soft delete 최종 UI가 통과하고 Community detail GET·detail route 호출은 0건이다. server mode는 별도 결과를 기록한다.
---
---
## Phase 6. FanTalk vertical slice
## Phase 7. FanTalk vertical slice
**목표:** 모든 viewport에서 FanTalk를 최신순·답변 상태로 조회하고 답변을 한 번 작성한 뒤 기존 답변만 수정한다.
**목표:** 모든 viewport에서 FanTalk를 최신순·답변 상태로 조회하고 답변을 한 번 작성한 뒤 기존 답변만 수정한다.
**Goal 실행 `P6-GATE`:** FanTalk 단일 답변 불변식과 모든 viewport journey를 최종 판정한다.
**Goal 실행 `P7-GATE`:** FanTalk mock UI journey와 실제 server integration 상태를 분리해 판정한다.
- **시작 조건:** `P6-T1`~`P6-T3` 활성 범위 완료.
- **시작 조건:** `P7-T1`~`P7-T3` 활성 범위 완료.
- **완료 증거:** 아래 명령과 Expected 통과 또는 Phase 제외 결정의 검증 기록.
- **완료 증거:** 아래 명령과 Expected 통과 또는 Phase 제외 결정의 검증 기록.
- **범위 밖:** 계약 미제공 상태에서 network integration 완료 주장.
- **범위 밖:** 계약 미제공 상태에서 network integration 완료 주장.
```bash
```bash
npm run test:run -- src/features/fan-talks
npm run test:run -- src/features/fan-talks
npm run e2e:mock -- tests/e2e/fan-talk.spec.ts
npm run e2e -- tests/e2e/fan-talk.spec.ts
npm run e2e -- tests/e2e/fan-talk.spec.ts
npm run typecheck
npm run typecheck
npm run lint
npm run lint
npm run build
npm run build
```
```
**Expected:** 미답변 조회 → 답변 1회 생성 → 기존 답변 수정이 모든 viewport에서 통과하며 두 번째 reply 생성과 delete UI가 없다.
**Expected:** 핵심 계약 제공 후 mock mode에서 미답변 조회 → 답변 1회 생성 → 기존 답변 수정 최종 UI가 모든 viewport에서 통과하며 두 번째 reply 생성과 delete UI가 없다. 계약 미제공이면 mock fixture도 만들지 않고 연동 대기로 기록한다.
---
---
## Phase 7. Comments vertical slice
## Phase 8. Comments vertical slice
**목표:** Audio detail과 Community Sheet 양쪽에서 같은 2단계 댓글 UX를 제공하고 작성자별 수정·soft delete 권한을 일관되게 적용한다.
**목표:** Audio detail과 Community Sheet 양쪽에서 같은 2단계 댓글 UX를 제공하고 작성자별 수정·soft delete 권한을 일관되게 적용한다.
**Goal 실행 `P7-GATE`:**두 target의 2단계 CRUD·권한·모바일 journey를 최종 판정한다.
**Goal 실행 `P8-GATE`:**Comments mock UI journey와 실제 server integration 상태를 분리해 판정한다.
- **시작 조건:** `P7-T1`~`P7-T4` 활성 범위 완료.
- **시작 조건:** `P8-T1`~`P8-T4` 활성 범위 완료.
- **완료 증거:** 아래 명령과 Expected 통과 또는 Phase 제외 결정의 검증 기록.
- **완료 증거:** 아래 명령과 Expected 통과 또는 Phase 제외 결정의 검증 기록.
- **범위 밖:** 계약 미제공 상태에서 network integration 완료 주장.
- **범위 밖:** 계약 미제공 상태에서 network integration 완료 주장.
```bash
```bash
npm run test:run -- src/features/comments
npm run test:run -- src/features/comments
npm run e2e:mock -- tests/e2e/comments.spec.ts
npm run e2e -- tests/e2e/comments.spec.ts
npm run e2e -- tests/e2e/comments.spec.ts
npm run typecheck
npm run typecheck
npm run lint
npm run lint
npm run build
npm run build
```
```
**Expected:** Audio와 Community 두 진입점에서 2단계 댓글 CRUD·권한·모바일 흐름이 통과하고 reply의 reply 및 fan edit request는 생성되지 않는다.
**Expected:** 핵심 계약 제공 후 mock mode에서 Audio와 Community 두 진입점의 2단계 댓글 CRUD·권한·모바일 최종 UI가 통과하고 reply의 reply 및 fan edit request는 생성되지 않는다. 계약 미제공이면 mock fixture도 만들지 않고 연동 대기로 기록한다.
---
---
## Phase 8. 교차 회귀·인수인계
## Phase 9. 교차 회귀·인수인계
**목표:** 새 기능을 추가하지 않고 활성 릴리스 범위 전체가 PRD, API Contract, 보안, 반응형, 접근성 기준을 만족한다는 최신 증거를 남긴다.
**목표:** 새 기능을 추가하지 않고 활성 릴리스 범위 전체가 PRD, API Contract, 보안, 반응형, 접근성 기준을 만족한다는 최신 증거를 남긴다.
**Phase Goal `P8`:** Task 8.1 → 8.3과 Phase 8 Gate로 활성 릴리스 범위의 최종 인수 증거를 완성한다.
**Phase Goal `P9`:** Task 9.1 → 9.3과 Phase 9 Gate로 활성 릴리스 범위의 최종 인수 증거를 완성한다.
- **시작 조건:** 활성 범위의 `P0-GATE`~`P7-GATE` 완료 또는 명시적 제외 결정.
- **시작 조건:** 활성 범위의 `P0-GATE`~`P8-GATE` 완료 또는 명시적 제외 결정.
- **완료 조건:** `P8-T1`~`P8-T3`, `P8-GATE` 완료, 전체 자동 Gate 0 failure/0 error와 수동 검증 기록.
- **완료 조건:** `P9-T1`~`P9-T3`, `P9-GATE` 완료, mock/server 전체 자동 Gate 0 failure/0 error와 수동 검증 기록.
**Expected:**전체 자동 Gate가 0 failure/0 error이고, `assert_no_match`는 no-match인 `rg` exit 1만 성공으로 바꾸며 `rg` 실행 오류는 실패로 전파한다. production source의 금지 값과 미완료 placeholder는 0건이어야 한다. 부정 test fixture의 금지 문자열은 허용하며 production 결과와 구분한다.
**Expected:**mock UI 전체 journey와 실제 server integration 결과가 분리 기록되고 production mock 활성화·404 자동 fallback이 0건이다. 전체 자동 Gate는 0 failure/0 error이며 production source의 금지 값과 미완료 placeholder는 0건이다.
| 9 | §9~10, §12~14, 활성 범위 전체 | 전체 unit/integration/mock·server E2E/build |
`FILE-001~015`의 domain-neutral component mechanics는 Phase 1에서 먼저 만든다. Character·Audio·Series·Community Phase는 자신의 allowed type·crop profile·GIF 예외와 multipart 흐름을 소유하면서 공통 mechanics를 조합·검증하고, Phase 8에서 전체 matrix를 회귀 검증한다.
`FILE-001~015`의 domain-neutral component mechanics는 Phase 1에서 먼저 만들고 browser mock 기반은 Phase 2가 소유한다. Character·Audio·Series·Community Phase는 자신의 allowed type·crop profile·GIF 예외, multipart handler와 fixture 흐름을 소유하며 Phase 9에서 mock/server 전체 matrix를 회귀 검증한다.
## 6. 구현 완료 정의
## 6. 구현 완료 정의
- [ ] Phase 0~7의 활성 범위 Gate와 Phase 8 전체 Gate가 최신 실행에서 통과한다.
- [ ] Phase 0~8의 활성 범위 Gate와 Phase 9 전체 Gate가 최신 실행에서 통과한다.
- [ ] 모든 **확정** 요구사항이 구현, 명시적 non-goal, 또는 결정 기록이 있는 후속 범위 중 하나로 추적된다.
- [ ] 모든 **확정** 요구사항이 구현, 명시적 non-goal, 또는 결정 기록이 있는 후속 범위 중 하나로 추적된다.
- [ ] 외부 의존을 추정 endpoint·placeholder DTO·임시 production mock으로 우회하지 않았다.
- [ ] 외부 의존을 추정 endpoint·placeholder DTO·임시 production mock으로 우회하지 않았다.
- [ ] 제공 계약 범위는 `dev:mock`에서 최종 UI를 확인할 수 있고, 계약 미제공 범위는 fixture로 추정하지 않았다.
- [ ] 각 도메인의 `UI 확인 완료(mock)`와 `실제 서버 연동 완료(server)` 상태와 증거가 분리돼 있다.
- [ ] server mode의 404·network error가 mock으로 자동 fallback되지 않고 production build에서 browser mock이 활성화되지 않는다.
### Mock Preview Phase 추가 및 후속 Phase 재번호 — 2026-07-27
- 무엇을: 제공된 API Contract 범위에서 backend 구현 전 최종 UI를 확인할 수 있도록 개발 전용 browser MSW 요구사항과 계약 경계를 추가하고, 완료된 Phase 0~1 다음에 신규 Phase 2를 배치했다. 기존 Character~최종 인수인계 Phase는 Phase 3~9로 이동하고 모든 활성 Task·Goal·Gate·의존성·추적표를 함께 재번호했다.
- 왜: 실제 API의 404를 mock으로 자동 대체하지 않으면서도 frontend가 최종 화면을 개발·검토할 수 있고, mock UI 확인과 실제 server integration 완료를 혼동하지 않기 위해서다.
- 어떻게:
- PRD `MOCK-001~009`, API Contract §1.5, Phase 2의 Task 2.1~2.3과 Gate 대조 — explicit `server | mock` mode, production 차단, no-auto-fallback, deterministic in-memory store와 mock banner 규칙 일치 확인.
- 활성 계획 검사 — Phase·Phase Goal·Gate·Gate Goal 각각 10개, 일반 구현 Task·Task Goal 각각 37개, Goal 선언 중복 0건, 활성 영역의 이전 Phase 번호 참조 0건.
- 문서 동기화 검사 — `docs/agent-guide/{prd,goal-plan}.md`와 `docs/sample/{sample-prd,sample-plan-task}.md` 4개 모두 같은 mock 작성 규칙 포함, 미구현 `docs/agent-guide/{environment,scripts}.md`의 `dev:mock`·`e2e:mock`·`VITE_API_MODE` 선반영 0건.
- Markdown fence 짝수 여부와 수정 문서의 내부 link 검사 — 이상 0건.
-`git diff --check -- <수정 문서 7개>` — 성공.
- 애플리케이션 test/build는 구현 코드와 설정을 변경하지 않았고 신규 명령도 아직 계획 상태이므로 실행하지 않는다.
- 남은 항목: Phase 2 구현 시 실제 `dev:mock`·`e2e:mock` 명령과 환경 변수를 만든 후 README와 `docs/agent-guide/{environment,scripts}.md`를 실체에 맞게 갱신한다. 계약 미제공 도메인은 backend 계약 수신 전 fixture를 만들지 않는다.
@@ -86,6 +86,7 @@ AI 캐릭터를 생성하고, AI 캐릭터가 사람 크리에이터처럼 콘
- 정식 WCAG 2.2 AA 인증 또는 외부 접근성 감사
- 정식 WCAG 2.2 AA 인증 또는 외부 접근성 감사
- 백엔드가 담당할 creator 생성·프로필 동기화의 조건부 정책 변경
- 백엔드가 담당할 creator 생성·프로필 동기화의 조건부 정책 변경
- 비활성 ID에 대한 상세 GET 반환 여부와 오류 status 등 백엔드 조회 정책 결정
- 비활성 ID에 대한 상세 GET 반환 여부와 오류 status 등 백엔드 조회 정책 결정
- 실제 API의 404를 감지해 mock 응답으로 자동 전환하는 production fallback
## 5. Target Users
## 5. Target Users
@@ -333,6 +334,20 @@ AI 캐릭터를 생성하고, AI 캐릭터가 사람 크리에이터처럼 콘
| FILE-014 | 확정 | 커뮤니티 GIF의 원본 가로가 800px을 초과하면 등록을 거부한다. client에서 제출 전에 차단하고 server도 같은 제한을 검증한다. GIF를 축소·crop·재인코딩하지 않는다. |
| FILE-014 | 확정 | 커뮤니티 GIF의 원본 가로가 800px을 초과하면 등록을 거부한다. client에서 제출 전에 차단하고 server도 같은 제한을 검증한다. GIF를 축소·crop·재인코딩하지 않는다. |
| FILE-015 | 확정 | Series crop 결과의 세로 pixel은 `round(width × 297 ÷ 210)`으로 계산한다. 최대 폭에서는 1,000×1,414px이며 비율 검증은 계산된 세로값 기준 1px 이내 오차를 허용한다. |
| FILE-015 | 확정 | Series crop 결과의 세로 pixel은 `round(width × 297 ÷ 210)`으로 계산한다. 최대 폭에서는 1,000×1,414px이며 비율 검증은 계산된 세로값 기준 1px 이내 오차를 허용한다. |
### 8.9 개발 전용 Mock Preview
| ID | 상태 | 요구사항 |
|---|---|---|
| MOCK-001 | 확정 | 개발 환경은 명시적인 `server`와 `mock` API mode를 제공한다. 기본 `npm run dev`는 실제 개발 API를 사용하고 `npm run dev:mock`만 browser MSW를 활성화한다. |
| MOCK-002 | 확정 | mock mode도 production과 같은 Page, Query, API client, endpoint path, request serializer와 response DTO를 사용한다. 별도 화면이나 mock 전용 API adapter를 만들지 않는다. |
| MOCK-003 | 확정 | 실제 API의 404·network error를 감지해 mock으로 자동 fallback하지 않는다. `server` mode의 오류는 실제 오류 UI로 처리한다. |
| MOCK-004 | 확정 | production build에서는 mock mode를 거부하고 browser worker·fixture가 활성화되지 않는다. |
| MOCK-005 | 확정 | 계약이 제공됐지만 backend endpoint가 아직 구현되지 않은 기능은 정규화 API Contract 기반 fixture와 browser handler로 최종 UI의 happy path를 확인할 수 있다. |
| MOCK-006 | 확정 | endpoint·DTO·오류 계약 자체가 미제공인 기능은 fixture를 추정하지 않는다. 계약과 무관한 shell·상태 inventory만 구현하고 최종 network UI 완료를 주장하지 않는다. |
| MOCK-007 | 확정 | 각 도메인 mock은 deterministic seed와 새로고침 시 초기화되는 in-memory store를 사용해 목록·상세·생성·수정·soft delete의 연결된 흐름을 재현한다. |
| MOCK-008 | 확정 | mock mode 화면에는 실제 서버가 아니라는 지속적으로 보이는 안내를 제공하고, JWT·password·signed URL·업로드 파일 본문을 log나 영구 저장소에 기록하지 않는다. |
| MOCK-009 | 확정 | 도메인 완료 상태는 `UI 확인 완료(mock)`와 `실제 서버 연동 완료(server)`를 분리한다. mock Gate만 통과한 경우 Phase 전체와 network integration을 완료로 표시하지 않는다. |
“가로 800/1,000”은 이 문서에서 등록 결과의 **최대 출력 폭**으로 해석한다. JPEG/PNG crop 결과에는 이 제한을 적용하되 선택한 원본 crop 영역이 더 작으면 확대하지 않는다. 커뮤니티 GIF는 원본 가로가 800px 이하일 때만 등록할 수 있다.
“가로 800/1,000”은 이 문서에서 등록 결과의 **최대 출력 폭**으로 해석한다. JPEG/PNG crop 결과에는 이 제한을 적용하되 선택한 원본 crop 영역이 더 작으면 확대하지 않는다. 커뮤니티 GIF는 원본 가로가 800px 이하일 때만 등록할 수 있다.
#### Image crop UI 흐름
#### Image crop UI 흐름
@@ -678,6 +693,8 @@ Phase 2~6에서 추가되는 오류는 구현 전에 정확한 비2xx status와
- 목록 검색 debounce 시간은 구현 시 300ms 전후로 일관되게 적용한다.
- 목록 검색 debounce 시간은 구현 시 300ms 전후로 일관되게 적용한다.
- 날짜, 가격, 상태 label은 중앙 formatter로 일관되게 표시한다.
- 날짜, 가격, 상태 label은 중앙 formatter로 일관되게 표시한다.
- 브라우저 지원 범위는 데스크톱 Chrome/Edge/Safari 최신 2개 주요 버전과 모바일 Chrome/Safari 최신 2개 주요 버전이다.
- 브라우저 지원 범위는 데스크톱 Chrome/Edge/Safari 최신 2개 주요 버전과 모바일 Chrome/Safari 최신 2개 주요 버전이다.
- mock/server mode는 build-time 환경 설정으로 명시적으로 선택하며 runtime 404 fallback을 사용하지 않는다.
- domain fixture와 browser handler는 `api-contract.md`의 제공 계약에서 파생하고 contract test와 함께 변경한다.
## 14. 성공 기준
## 14. 성공 기준
@@ -714,6 +731,10 @@ Phase 2~6에서 추가되는 오류는 구현 전에 정확한 비2xx status와
- FanTalk 답변이 있으면 두 번째 POST가 UI에서 차단되고 수정 동작만 제공되며, 직접·동시 요청도 백엔드가 원자적으로 거부한다.
- FanTalk 답변이 있으면 두 번째 POST가 UI에서 차단되고 수정 동작만 제공되며, 직접·동시 요청도 백엔드가 원자적으로 거부한다.
- 댓글은 2단계를 넘지 않고 작성자에 따른 수정·삭제 권한이 구분된다.
- 댓글은 2단계를 넘지 않고 작성자에 따른 수정·삭제 권한이 구분된다.
- 모바일에서 조회·오디오 재생·댓글 관리·FanTalk 답변 작성/수정이 가능하다.
- 모바일에서 조회·오디오 재생·댓글 관리·FanTalk 답변 작성/수정이 가능하다.
-`npm run dev:mock`에서 실제 backend 요청 없이 제공 계약 범위의 최종 UI happy path를 확인할 수 있고 mock mode 안내가 표시된다.
- 기본 `npm run dev`에서는 실제 개발 API를 사용하며 404·network error가 mock 응답으로 바뀌지 않는다.
- production build에는 browser mock이 활성화되지 않고 mock mode 설정을 허용하지 않는다.
- 각 도메인의 Progress와 Phase Gate는 `UI 확인 완료(mock)`와 `실제 서버 연동 완료(server)` 증거를 별도로 기록한다.
### 14.2 UI/UX 수용 기준
### 14.2 UI/UX 수용 기준
@@ -773,3 +794,4 @@ Phase 2~6에서 추가되는 오류는 구현 전에 정확한 비2xx status와
| 2026-07-26 | 문자열 최대 길이와 배열 최대 개수는 초기 UI 작성 후 각 페이지에서 권고값을 정하고 백엔드 호환 확인 후 확정한다. 그 전에는 제공 계약에 없는 최대값을 추정하지 않는다. |
| 2026-07-26 | 문자열 최대 길이와 배열 최대 개수는 초기 UI 작성 후 각 페이지에서 권고값을 정하고 백엔드 호환 확인 후 확정한다. 그 전에는 제공 계약에 없는 최대값을 추정하지 않는다. |
| 2026-07-26 | 댓글 API·팬 댓글 삭제 권한 오류와 FanTalk 목록·상세·답변 수정·중복 답변 계약은 백엔드 제공 대기 사항으로 분류하고 프론트엔드 Open Questions에서 제외한다. |
| 2026-07-26 | 댓글 API·팬 댓글 삭제 권한 오류와 FanTalk 목록·상세·답변 수정·중복 답변 계약은 백엔드 제공 대기 사항으로 분류하고 프론트엔드 Open Questions에서 제외한다. |
| 2026-07-27 | 오디오 콘텐츠 생성에는 `themeId`가 필수이며, 테마 선택지는 `GET /api/v2/admin/ai-characters/audio-content-themes`에서 query/body 없이 조회한다. |
| 2026-07-27 | 오디오 콘텐츠 생성에는 `themeId`가 필수이며, 테마 선택지는 `GET /api/v2/admin/ai-characters/audio-content-themes`에서 query/body 없이 조회한다. |
| 2026-07-27 | backend endpoint 구현 전에도 제공된 API Contract 범위의 최종 UI를 확인할 수 있도록 명시적 개발 전용 browser MSW mode를 제공한다. 실제 404 자동 fallback은 금지하고 mock UI 완료와 실제 server 연동 완료를 분리한다. |
@@ -211,6 +211,7 @@ Non-Goal을 변경하려면 Decision Log와 `plan-task.md` 범위를 먼저 갱
- mutation 중복 제출·upload 취소/재시도: `<정책>`
- mutation 중복 제출·upload 취소/재시도: `<정책>`
- 지원 runtime·browser: `<정확한 범위>`
- 지원 runtime·browser: `<정확한 범위>`
- test stack과 필수 Gate: `<unit/integration/E2E/typecheck/lint/build>`
- test stack과 필수 Gate: `<unit/integration/E2E/typecheck/lint/build>`
- backend 구현 전 UI 확인: `<불필요 또는 explicit mock mode, production 금지, no-auto-fallback, mock/server 완료 상태 분리>`
## 14. 성공 기준
## 14. 성공 기준
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.