docs(ai-character): Mock Preview 계획 추가
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
|
||||
| 문서 항목 | 내용 |
|
||||
|---|---|
|
||||
| 상태 | Phase 0~1 완료, Phase 2 착수 전 |
|
||||
| 상태 | Phase 0~1 완료, 신규 Phase 2 Mock Preview 착수 전 |
|
||||
| 최초 작성일 | 2026-07-25 |
|
||||
| 재작성일 | 2026-07-26 |
|
||||
| 요구사항 기준 | [prd.md](./prd.md) |
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
## 1. 전역 제약
|
||||
|
||||
- 이번 단계에서는 이 계획 문서만 수정한다. 애플리케이션 코드와 프로젝트 설정은 후속 구현 단계에서 변경한다.
|
||||
- 계획 보완 단계에서는 PRD·API Contract·plan과 연결 가이드만 동기화하고, 애플리케이션 코드와 프로젝트 설정은 해당 Task goal 실행 때 변경한다.
|
||||
- PRD와 최초 API Contract가 충돌하면 PRD `11.4 API 계약 보정사항`을 우선한다.
|
||||
- 로그인은 `POST /admin/member/login`, 로그아웃은 body 없는 `POST /member/logout`을 사용한다.
|
||||
- JWT와 ADMIN role은 `sessionStorage`에만 저장한다. refresh token과 자동 갱신은 구현하지 않는다.
|
||||
@@ -42,18 +42,23 @@
|
||||
- Page는 routing·query·permission·component 조합만 담당한다. 도메인 표시와 상호작용은 feature component로, 두 Phase 이상에서 의미와 동작이 같은 것은 shared component로 분리한다.
|
||||
- 단순 markup 한 조각, 한 화면 전용 UI, 서로 다른 도메인 규칙을 하나의 범용 prop API로 합치기 위한 component는 만들지 않는다.
|
||||
- 모든 기능은 실패하는 test를 먼저 만들고 최소 구현으로 통과시킨다.
|
||||
- API mode는 `server | mock`을 명시적으로 선택한다. 기본 `npm run dev`는 실제 개발 API, `npm run dev:mock`은 browser MSW를 사용한다.
|
||||
- 실제 API의 404·network error를 감지한 자동 mock fallback은 만들지 않고 production build에서는 mock mode를 거부한다.
|
||||
- 제공 계약이 있는 기능만 contract 기반 browser fixture를 만들며, 계약 자체가 없으면 최종 network UI를 추정 구현하지 않는다.
|
||||
- 각 도메인은 `UI 확인 완료(mock)`와 `실제 서버 연동 완료(server)`를 별도 증거로 기록하며 mock Gate만으로 Phase 전체 완료를 주장하지 않는다.
|
||||
|
||||
## 2. Phase 운영 규칙
|
||||
|
||||
### 2.1 독립 검증 규칙
|
||||
|
||||
각 Phase는 다음 결과를 모두 가진다.
|
||||
각 도메인 Phase는 다음 결과를 모두 가진다.
|
||||
|
||||
1. 사용자가 직접 확인할 수 있는 하나 이상의 완결된 흐름
|
||||
2. 해당 Phase가 소유하는 API contract test
|
||||
3. loading·empty·error·success 상태
|
||||
4. 해당 viewport 범위와 keyboard·접근성 검증
|
||||
5. Phase 전용 E2E와 공통 typecheck·lint·build 결과
|
||||
6. 제공 계약 범위의 mock preview E2E와 backend 구현 후 server integration 결과를 구분한 기록
|
||||
|
||||
각 Task는 다음 Red/Green loop를 따른다.
|
||||
|
||||
@@ -126,24 +131,26 @@ Goal objective 권장 형식:
|
||||
|---:|---|---|---|
|
||||
| 0 | 프로젝트 세팅 | 없음 | fresh install, root smoke, unit/E2E/build |
|
||||
| 1 | 공통 플랫폼·인증/인가·컴포넌트 기반 | Phase 0 | shared component contract + login → protected shell → refresh restore → logout/401/403 |
|
||||
| 2 | Character workspace | Phase 1 | list/search → create/select → detail/edit → deactivate |
|
||||
| 3 | Audio vertical slice | Phase 2의 workspace core | list/filter/detail/play → create/edit/upload → deactivate |
|
||||
| 4 | Series vertical slice | Phase 3의 Audio 조회 API | CRUD → content link/unlink → full reorder |
|
||||
| 5 | Community vertical slice | Phase 3의 media/file primitive | list → collection Sheet edit/pin → media play → deactivate |
|
||||
| 6 | FanTalk vertical slice | Phase 2 | list/filter/detail → one reply → edit |
|
||||
| 7 | Comments vertical slice | Phase 3 + Phase 5 | Audio/Community thread → permission별 CRUD |
|
||||
| 8 | 교차 회귀·인수인계 | 활성 범위의 Phase 0~7 | 전체 journey, viewport, axe, security, build |
|
||||
| 2 | 개발 전용 Mock Preview 기반 | Phase 1 | explicit mock/server mode, browser MSW, mock banner, no production fallback |
|
||||
| 3 | Character workspace | Phase 2 | list/search → create/select → detail/edit → deactivate |
|
||||
| 4 | Audio vertical slice | Phase 3의 workspace core | list/filter/detail/play → create/edit/upload → deactivate |
|
||||
| 5 | Series vertical slice | Phase 4의 Audio 조회 API | CRUD → content link/unlink → full reorder |
|
||||
| 6 | Community vertical slice | Phase 4의 media/file primitive | list → collection Sheet edit/pin → media play → deactivate |
|
||||
| 7 | FanTalk vertical slice | Phase 3 | list/filter/detail → one reply → edit |
|
||||
| 8 | Comments vertical slice | Phase 4 + Phase 6 | Audio/Community thread → permission별 CRUD |
|
||||
| 9 | 교차 회귀·인수인계 | 활성 범위의 Phase 0~8 | 전체 journey, viewport, axe, security, mock/server build |
|
||||
|
||||
기본 진행 순서는 Phase 번호를 따른다. 다만 Phase 4·5·6은 자신의 선행조건과 계약이 충족되면 병행할 수 있고, 외부 계약으로 막힌 Phase가 다른 독립 Phase를 막지 않는다.
|
||||
기본 진행 순서는 Phase 번호를 따른다. 다만 Phase 5·6·7은 자신의 선행조건과 계약이 충족되면 병행할 수 있고, 외부 계약으로 막힌 Phase가 다른 독립 Phase를 막지 않는다.
|
||||
|
||||
```text
|
||||
Phase 0 Setup
|
||||
└─ Phase 1 Platform + Auth/Authz + Shared Components
|
||||
└─ Phase 2 Character Workspace
|
||||
├─ Phase 3 Audio ──┬─ Phase 4 Series
|
||||
│ └─ Phase 5 Community ──┐
|
||||
└─ Phase 6 FanTalk ├─ Phase 8 Final
|
||||
Phase 3 + Phase 5 ── Phase 7 Comments ┘
|
||||
└─ Phase 2 Mock Preview Foundation
|
||||
└─ Phase 3 Character Workspace
|
||||
├─ Phase 4 Audio ──┬─ Phase 5 Series
|
||||
│ └─ Phase 6 Community ──┐
|
||||
└─ Phase 7 FanTalk ├─ Phase 9 Final
|
||||
Phase 4 + Phase 6 ── Phase 8 Comments ┘
|
||||
```
|
||||
|
||||
## 4. 파일 책임 지도
|
||||
@@ -407,13 +414,13 @@ npm run build:prod
|
||||
|
||||
- **시작 조건:** `P1-T3` 완료.
|
||||
- **완료 증거:** 체크박스 전체, route/shell test, auth·accessibility E2E와 viewport/axe 기록.
|
||||
- **범위 밖:** Phase 2 Character 데이터와 mutation.
|
||||
- **범위 밖:** Phase 3 Character 데이터와 mutation.
|
||||
|
||||
- [x] 미인증 사용자가 보호 content를 한 프레임도 보지 않고 `/login`으로 이동하는 test를 작성한다.
|
||||
- [x] 401은 session 제거 후 login, 403은 AccessDeniedPage로 가는 route test를 작성한다.
|
||||
- [x] desktop sidebar, mobile Sheet, header, logout, breadcrumb, skip link, `main` landmark를 구현한다.
|
||||
- [x] keyboard로 login, navigation, logout을 완료하고 dialog/menu focus가 trigger로 복귀하는 test를 작성한다.
|
||||
- [x] `/ai-characters`에는 Phase 2가 교체할 명시적 빈 route state만 두고 가짜 도메인 데이터를 만들지 않는다.
|
||||
- [x] `/ai-characters`에는 Phase 3이 교체할 명시적 빈 route state만 두고 가짜 도메인 데이터를 만들지 않는다.
|
||||
- [x] 320px과 200% zoom에서 shell overflow와 가려진 control이 없는지 E2E로 확인한다.
|
||||
- [x] shell route의 axe critical·serious 위반 0건을 확인한다.
|
||||
|
||||
@@ -489,7 +496,7 @@ npm run build
|
||||
|
||||
- 연결 리뷰: `REV-P1-002`, `REV-P1-006`, `REV-P1-007`
|
||||
- 완료 증거: stale ADMIN probe pending·403 동안 보호 shell 비노출, probe `size=20`, 서버 한국어 message 우선 표시, logout in-flight 중 API 1회 호출.
|
||||
- 범위 밖: 인증 방식 또는 token 저장 방식 교체, Phase 2 권한 기능.
|
||||
- 범위 밖: 인증 방식 또는 token 저장 방식 교체, Phase 3 권한 기능.
|
||||
|
||||
- [x] 지연 403 전 보호 shell 비노출과 probe `size=20` request assertion을 `src/app/App.test.tsx`에 추가했다.
|
||||
- [x] 로그인 실패 시 `Error.message`의 서버 한국어 message를 우선 표시하도록 `LoginPage`를 수정했다.
|
||||
@@ -567,14 +574,103 @@ npm run build
|
||||
|
||||
---
|
||||
|
||||
## Phase 2. Character workspace vertical slice
|
||||
## Phase 2. 개발 전용 Mock Preview 기반
|
||||
|
||||
**목표:** backend endpoint 구현 전에도 제공된 API Contract 범위의 최종 UI를 브라우저에서 확인하고, 명시적 전환으로 실제 개발 API와 같은 frontend code를 사용한다.
|
||||
|
||||
**Phase Goal `P2`:** Task 2.1 → 2.3과 Phase 2 Gate로 browser MSW 기반 mock preview와 server mode 경계를 완성한다.
|
||||
|
||||
- **시작 조건:** `P1-GATE` 완료.
|
||||
- **완료 조건:** `P2-T1`~`P2-T3`, `P2-GATE` 완료. mock/server 분리와 production 차단이 자동 test와 E2E로 고정됨.
|
||||
- **현재 상태:** Phase 1 완료 후 새로 추가된 독립 후속 Phase. Phase 0·1의 완료 이력은 변경하지 않는다.
|
||||
|
||||
**요구사항:** `MOCK-001~009`, PRD `11.1~11.2`, `12`, `13`.
|
||||
|
||||
**주요 Files:**
|
||||
|
||||
- Modify: `package.json`, `.env.example`, `src/shared/config/env.ts`, `src/shared/config/env.test.ts`
|
||||
- Modify: `src/main.tsx`, `src/app/providers.tsx`
|
||||
- Create: `src/shared/mocks/{browser,handlers,fixtures,store}.ts`
|
||||
- Create: `src/shared/mocks/__tests__/{mode-boundary,handlers,store}.test.ts`
|
||||
- Create: `src/shared/ui/mock-mode-banner.tsx`
|
||||
- Create: `src/shared/ui/__tests__/mock-mode-banner.test.tsx`
|
||||
- Create: `public/mockServiceWorker.js`
|
||||
- Create: `tests/e2e/mock-preview-shell.spec.ts`
|
||||
- Modify when implementation is complete: `README.md`, `docs/agent-guide/{environment,scripts}.md`
|
||||
|
||||
### Task 2.1 explicit API mode·production 경계
|
||||
|
||||
**Goal 실행 `P2-T1`:** `server | mock` mode와 dev-only browser worker bootstrap을 구성하고 자동 fallback·production mock을 차단한다.
|
||||
|
||||
- **시작 조건:** `P1-GATE` 완료, PRD `MOCK-001~006` 확인.
|
||||
- **완료 증거:** env/script/bootstrap focused test, `dev` server 기본값, `dev:mock` explicit mode, production mock 거부와 404 no-fallback test.
|
||||
- **범위 밖:** Character 이후 도메인 fixture와 실제 backend endpoint 구현.
|
||||
|
||||
- [ ] `VITE_API_MODE=server | mock`을 검증하고 누락 기본값은 `server`로 고정하는 실패 test를 작성한다.
|
||||
- [ ] `npm run dev:mock`만 Vite mock mode와 browser worker를 시작하고 기본 `npm run dev`는 실제 `VITE_API_BASE_URL`을 사용하는 script test를 작성한다.
|
||||
- [ ] Playwright가 같은 spec을 explicit mode로 실행할 수 있도록 `e2e:mock`과 server mode 명령을 정의하고 각 webServer 환경을 test한다.
|
||||
- [ ] `import.meta.env.DEV && apiMode === "mock"`일 때만 browser module을 dynamic import하고 worker 준비 후 React를 mount한다.
|
||||
- [ ] production mode에서 `mock`을 설정하면 build/start 전에 설명 가능한 오류로 거부하고 worker·fixture가 production graph에서 실행되지 않는 test를 작성한다.
|
||||
- [ ] `server` mode의 404·network error가 browser mock을 시작하거나 응답을 교체하지 않는 test를 작성한다.
|
||||
- [ ] worker의 unhandled request 정책은 error로 두어 누락된 handler가 실제 backend로 조용히 통과하지 않게 한다.
|
||||
|
||||
### Task 2.2 공통 preview session·fixture store
|
||||
|
||||
**Goal 실행 `P2-T2`:** production API 경계를 그대로 사용하는 deterministic auth fixture, in-memory store와 mock mode 안내를 완성한다.
|
||||
|
||||
- **시작 조건:** `P2-T1` 완료, API Contract §1·§3 확인.
|
||||
- **완료 증거:** auth handler/store/banner focused test와 login → protected shell mock preview E2E 기록.
|
||||
- **범위 밖:** 도메인별 endpoint handler와 계약 미제공 fixture.
|
||||
|
||||
- [ ] fixture는 정규화 `ApiResponse<T>`와 실제 endpoint·header·body contract를 사용하고 별도 mock DTO를 만들지 않는다.
|
||||
- [ ] ADMIN login·logout, 401·403 fixture와 새로고침 시 seed로 초기화되는 in-memory store를 만든다.
|
||||
- [ ] mock mutation은 같은 store의 목록·상세 응답을 갱신하고 browser storage에 domain fixture를 영구 저장하지 않는다.
|
||||
- [ ] mock mode임을 지속적으로 표시하는 접근 가능한 banner와 server mode에서 banner가 없는 test를 작성한다.
|
||||
- [ ] JWT·password·signed URL·multipart body가 mock logger와 storage에 기록되지 않는 test를 작성한다.
|
||||
- [ ] 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까지 완료한다.
|
||||
|
||||
**Phase Goal `P2`:** Task 2.1 → 2.4와 Phase 2 Gate로 Character workspace vertical slice를 완성한다.
|
||||
**Phase Goal `P3`:** Task 3.1 → 3.4와 Phase 3 Gate로 Character workspace vertical slice를 완성한다.
|
||||
|
||||
- **시작 조건:** `P1-GATE` 완료.
|
||||
- **완료 조건:** `P2-T1`~`P2-T4`, `P2-GATE` 완료. 외부 의존은 구현 또는 명시적 제외 결정으로 종결.
|
||||
- **시작 조건:** `P2-GATE` 완료.
|
||||
- **완료 조건:** `P3-T1`~`P3-T4`, `P3-GATE` 완료. 외부 의존은 구현 또는 명시적 제외 결정으로 종결.
|
||||
- **실행 순서:** 계약 확인 → 목록/workspace → mutation → 반응형·접근성.
|
||||
|
||||
**요구사항:** `CHAR-001~014`, `FILE-001~002`, `FILE-008~010`, `FILE-012`, PRD `7`, `9`의 Character 범위.
|
||||
@@ -597,11 +693,11 @@ npm run build
|
||||
- Create: `tests/e2e/character-workspace.spec.ts`
|
||||
- Modify: `src/app/router.tsx`, `src/app/route-paths.ts`
|
||||
|
||||
### Task 2.1 Phase 계약 확인
|
||||
### Task 3.1 Phase 계약 확인
|
||||
|
||||
**Goal 실행 `P2-T1`:** Character 구현 계약과 화면 component map을 확정한다.
|
||||
**Goal 실행 `P3-T1`:** Character 구현 계약, mock scenario와 화면 component map을 확정한다.
|
||||
|
||||
- **시작 조건:** `P1-GATE` 완료, PRD `CHAR-001~014`와 API Contract §4 확인.
|
||||
- **시작 조건:** `P2-GATE` 완료, PRD `CHAR-001~014`, `MOCK-001~009`와 API Contract §4 확인.
|
||||
- **완료 증거:** 체크박스 전체, 제공 계약 또는 제외 결정의 세 문서 일치, 상태/action inventory.
|
||||
- **범위 밖:** 계약을 추정한 production adapter와 Character 화면 구현.
|
||||
|
||||
@@ -609,12 +705,13 @@ npm run build
|
||||
- [ ] 계약이 없으면 original work network control과 serializer를 추측하지 않고, 현재 slice에서 제외할 범위를 PRD·API Contract·plan에 먼저 기록한다.
|
||||
- [ ] Character 도메인 오류의 비2xx status와 message key를 contract fixture에 기록한다.
|
||||
- [ ] 목록·상세·form·workspace의 상태/action inventory를 작성하고 Page는 route/query/policy 조합, feature component는 Character 표시·입력 규칙, shared component는 Phase 1 contract를 사용하도록 component map을 확정한다.
|
||||
- [ ] 제공 계약 범위의 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 상태 검증 기록.
|
||||
- **범위 밖:** Character 생성·수정·비활성화 form.
|
||||
|
||||
@@ -625,12 +722,13 @@ npm run build
|
||||
- [ ] workspace header에 image, name, active 상태, `characterId`와 탭·breadcrumb를 표시한다.
|
||||
- [ ] 상세 성공 응답이 `isActive=false`이면 read-only 배너와 중앙 write policy로 모든 mutation 진입점을 차단한다.
|
||||
- [ ] 상세 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 규칙을 완성한다.
|
||||
|
||||
- **시작 조건:** `P2-T1`, `P2-T2` 완료.
|
||||
- **시작 조건:** `P3-T1`, `P3-T2` 완료.
|
||||
- **완료 증거:** 체크박스 전체, serializer/form/image/deactivate test, `OQ-009` 결정과 검증 기록.
|
||||
- **범위 밖:** 계약 미제공 original-work integration과 하위 도메인 mutation.
|
||||
|
||||
@@ -645,12 +743,13 @@ npm run build
|
||||
- [ ] 비활성화 AlertDialog가 영향·복원 미지원·hard delete 미지원을 설명하는 test를 작성한다.
|
||||
- [ ] soft delete 성공 후 active-only 목록 재조회, 목록 이동, 성공 toast를 확인하고 상세에 머물지 않는다.
|
||||
- [ ] Character form을 실제로 작성한 뒤 `OQ-009`의 `name`·`description` 상한 필요성을 판단하고, 구현 전 결정 문서를 갱신하거나 “상한 추가 없음”으로 종결한다.
|
||||
- [ ] mock store가 create/update/deactivate 후 목록·상세를 같은 server response contract로 갱신하는 E2E를 작성한다.
|
||||
|
||||
### Task 2.4 Character 반응형·접근성
|
||||
### Task 3.4 Character 반응형·접근성
|
||||
|
||||
**Goal 실행 `P2-T4`:** Character viewport capability와 keyboard·zoom·axe 기준을 검증한다.
|
||||
**Goal 실행 `P3-T4`:** Character viewport capability와 keyboard·zoom·axe 기준을 검증한다.
|
||||
|
||||
- **시작 조건:** `P2-T2`, `P2-T3`의 활성 범위 완료.
|
||||
- **시작 조건:** `P3-T2`, `P3-T3`의 활성 범위 완료.
|
||||
- **완료 증거:** 체크박스 전체, 320/768/1280px·200% zoom·keyboard·axe E2E 기록.
|
||||
- **범위 밖:** 다음 Phase 도메인과 모바일 mutation.
|
||||
|
||||
@@ -660,34 +759,35 @@ npm run build
|
||||
- [ ] keyboard-only로 search → select → tabs → form → dialog를 완료한다.
|
||||
- [ ] 320/768/1280px, 200% zoom, axe critical·serious 0건을 Phase E2E에서 확인한다.
|
||||
|
||||
### Phase 2 Gate
|
||||
### Phase 3 Gate
|
||||
|
||||
**Goal 실행 `P2-GATE`:** Character 전체 journey와 공통 품질 Gate를 최종 판정한다.
|
||||
**Goal 실행 `P3-GATE`:** Character mock UI journey와 실제 server integration 상태를 분리해 판정한다.
|
||||
|
||||
- **시작 조건:** `P2-T1`~`P2-T4` 완료.
|
||||
- **시작 조건:** `P3-T1`~`P3-T4` 완료.
|
||||
- **완료 증거:** 아래 명령과 Expected 통과, 외부 의존의 구현/제외 상태 기록.
|
||||
- **범위 밖:** 실패와 무관한 Audio 기능.
|
||||
|
||||
```bash
|
||||
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 typecheck
|
||||
npm run lint
|
||||
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를 안전하게 제어한다.
|
||||
|
||||
**Phase Goal `P3`:** Task 3.1 → 3.4와 Phase 3 Gate로 Audio 조회·재생·발행·upload slice를 완성한다.
|
||||
**Phase Goal `P4`:** Task 4.1 → 4.4와 Phase 4 Gate로 Audio 조회·재생·발행·upload slice를 완성한다.
|
||||
|
||||
- **시작 조건:** Phase 2 workspace core(`P2-T2`)와 `P1-T6` 완료.
|
||||
- **완료 조건:** `P3-T1`~`P3-T4`, `P3-GATE` 완료. 오류·price 계약은 제공값 또는 명시된 최소 규칙으로 종결.
|
||||
- **시작 조건:** Phase 3 workspace core(`P3-T2`)와 `P2-GATE` 완료.
|
||||
- **완료 조건:** `P4-T1`~`P4-T4`, `P4-GATE` 완료. 오류·price 계약은 제공값 또는 명시된 최소 규칙으로 종결.
|
||||
- **실행 순서:** 계약 확인 → 목록/상세/player → form/upload → 반응형·접근성.
|
||||
|
||||
**요구사항:** `AUDIO-001~028`, `FILE-001~002`, `FILE-006~009`, `FILE-012~013`, PRD `9`의 Audio 범위.
|
||||
@@ -706,11 +806,11 @@ npm run build
|
||||
- Create: `src/features/audio-contents/tests/{audio-list,audio-player,audio-form}.test.tsx`
|
||||
- Create: `tests/e2e/audio-content.spec.ts`
|
||||
|
||||
### Task 3.1 Phase 계약 확인
|
||||
### Task 4.1 Phase 계약 확인
|
||||
|
||||
**Goal 실행 `P3-T1`:** Audio 오류·price·theme·상태 계약과 component map을 확정한다.
|
||||
**Goal 실행 `P4-T1`:** Audio 오류·price·theme·상태 계약, mock scenario와 component map을 확정한다.
|
||||
|
||||
- **시작 조건:** `P2-T2`, `P1-T6` 완료, PRD `AUDIO-001~028`와 API Contract §5 확인.
|
||||
- **시작 조건:** `P3-T2`, `P2-GATE` 완료, PRD `AUDIO-001~028`, `MOCK-001~009`와 API Contract §5 확인.
|
||||
- **완료 증거:** 체크박스 전체, contract fixture와 상태/action inventory의 세 문서 일치.
|
||||
- **범위 밖:** 오류 status/key 또는 price 상한 추정과 Audio UI 구현.
|
||||
|
||||
@@ -719,12 +819,13 @@ npm run build
|
||||
- [ ] price 최대값이 제공되면 schema와 경계 test를 추가하고, 없으면 상한을 만들지 않는다.
|
||||
- [ ] status query 미전송 시 server가 결과 집합을 결정한다는 계약을 유지하고 client fixture에서 임의 집합을 강제하지 않는다.
|
||||
- [ ] 목록·상세·player·form/upload의 상태/action inventory를 작성하고 Page는 route/query/policy 조합, feature component는 Audio 규칙, shared component는 Phase 1 contract를 사용하도록 component map을 확정한다.
|
||||
- [ ] 제공 계약 범위의 Audio seed와 목록·상세·player·theme·upload CRUD browser handler 시나리오를 확정한다.
|
||||
|
||||
### Task 3.2 목록·상세·player
|
||||
### Task 4.2 목록·상세·player
|
||||
|
||||
**Goal 실행 `P3-T2`:** Audio active-only 목록·상세 복원과 안전한 단일 재생 흐름을 완성한다.
|
||||
**Goal 실행 `P4-T2`:** Audio active-only 목록·상세 복원과 안전한 단일 재생 흐름을 완성한다.
|
||||
|
||||
- **시작 조건:** `P3-T1` 완료.
|
||||
- **시작 조건:** `P4-T1` 완료.
|
||||
- **완료 증거:** 체크박스 전체, list/detail/player test와 signed URL 비기록·no-auto-refetch 기록.
|
||||
- **범위 밖:** 생성·수정·upload form.
|
||||
|
||||
@@ -736,12 +837,13 @@ npm run build
|
||||
- [ ] media error를 signed URL 만료로 추정하지 않고 일반 오류·수동 재시도·페이지 새로고침 안내를 표시한다.
|
||||
- [ ] media error만으로 목록/detail GET과 `play()`가 자동 재호출되지 않는 test를 작성한다.
|
||||
- [ ] signed URL이 log·storage·분석 event로 전달되지 않는 test를 작성한다.
|
||||
- [ ] mock mode는 실제 endpoint shape와 local preview audio asset으로 목록 → 상세 → 단일 재생 최종 UI를 확인한다.
|
||||
|
||||
### Task 3.3 발행 form·upload
|
||||
### Task 4.3 발행 form·upload
|
||||
|
||||
**Goal 실행 `P3-T3`:** theme 선택, 즉시/예약 발행, multipart media와 진행률·취소·재시도를 완성한다.
|
||||
**Goal 실행 `P4-T3`:** theme 선택, 즉시/예약 발행, multipart media와 진행률·취소·재시도를 완성한다.
|
||||
|
||||
- **시작 조건:** `P3-T1`, `P3-T2` 완료.
|
||||
- **시작 조건:** `P4-T1`, `P4-T2` 완료.
|
||||
- **완료 증거:** 체크박스 전체, contract/form/upload/file-boundary test, `OQ-009` 결정과 검증 기록.
|
||||
- **범위 밖:** resumable upload, client codec 판정, 계약 없는 price 상한.
|
||||
|
||||
@@ -761,12 +863,13 @@ npm run build
|
||||
- [ ] 415 server 오류를 field 안내로 보존하고 resumable upload는 만들지 않는다.
|
||||
- [ ] 저장 성공은 detail/list cache를 갱신하고 soft delete 성공은 active-only 목록 이동과 toast로 끝낸다.
|
||||
- [ ] Audio form을 실제로 작성한 뒤 `OQ-009`의 `title`·`description`·`seriesIds` 상한 필요성을 판단하고, 구현 전 결정 문서를 갱신하거나 “상한 추가 없음”으로 종결한다.
|
||||
- [ ] mock handler가 multipart request contract를 검증하고 create/update/deactivate 후 같은 store의 list/detail을 갱신하는 E2E를 작성한다.
|
||||
|
||||
### Task 3.4 Audio 반응형·접근성
|
||||
### Task 4.4 Audio 반응형·접근성
|
||||
|
||||
**Goal 실행 `P3-T4`:** Audio viewport capability와 player/form 접근성 기준을 검증한다.
|
||||
**Goal 실행 `P4-T4`:** Audio viewport capability와 player/form 접근성 기준을 검증한다.
|
||||
|
||||
- **시작 조건:** `P3-T2`, `P3-T3`의 활성 범위 완료.
|
||||
- **시작 조건:** `P4-T2`, `P4-T3`의 활성 범위 완료.
|
||||
- **완료 증거:** 체크박스 전체, 320px·keyboard·200% zoom·axe E2E 기록.
|
||||
- **범위 밖:** 모바일 create/edit/deactivate/upload.
|
||||
|
||||
@@ -775,34 +878,35 @@ npm run build
|
||||
- [ ] 320px에서 player control, error text, 긴 title이 overflow하지 않는 E2E를 작성한다.
|
||||
- [ ] keyboard-only player/form, 200% zoom, axe critical·serious 0건을 확인한다.
|
||||
|
||||
### Phase 3 Gate
|
||||
### Phase 4 Gate
|
||||
|
||||
**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 검증 기록.
|
||||
- **범위 밖:** 실패와 무관한 Series/Community 구현.
|
||||
|
||||
```bash
|
||||
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 typecheck
|
||||
npm run lint
|
||||
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 전체 순서를 관리한다.
|
||||
|
||||
**Phase Goal `P4`:** Task 4.1 → 4.4와 Phase 4 Gate로 Series CRUD·연결·전체 순서 slice를 완성한다.
|
||||
**Phase Goal `P5`:** Task 5.1 → 5.4와 Phase 5 Gate로 Series CRUD·연결·전체 순서 slice를 완성한다.
|
||||
|
||||
- **시작 조건:** `P3-T2`의 Audio 조회 API 완료.
|
||||
- **완료 조건:** `P4-T1`~`P4-T4`, `P4-GATE` 완료. 계약 없는 genre·연결·순서는 구현 또는 명시적 제외 결정으로 종결.
|
||||
- **시작 조건:** `P4-T2`의 Audio 조회 API 완료.
|
||||
- **완료 조건:** `P5-T1`~`P5-T4`, `P5-GATE` 완료. 계약 없는 genre·연결·순서는 구현 또는 명시적 제외 결정으로 종결.
|
||||
- **실행 순서:** 계약 확인 → CRUD → 연결/순서 → 반응형·접근성.
|
||||
|
||||
**요구사항:** `SERIES-001~013`, `FILE-001~002`, `FILE-005`, `FILE-007~009`, `FILE-012`, `FILE-015`, PRD `9`의 Series 범위.
|
||||
@@ -821,11 +925,11 @@ npm run build
|
||||
- Create: `src/features/series/tests/{series-form,series-contents,series-order}.test.tsx`
|
||||
- Create: `tests/e2e/series.spec.ts`
|
||||
|
||||
### Task 4.1 Phase 계약 확인
|
||||
### Task 5.1 Phase 계약 확인
|
||||
|
||||
**Goal 실행 `P4-T1`:** Series genre·연결 후보·전체 순서·오류 계약과 component map을 확정한다.
|
||||
**Goal 실행 `P5-T1`:** Series genre·연결 후보·전체 순서·오류 계약, mock scenario와 component map을 확정한다.
|
||||
|
||||
- **시작 조건:** `P3-T2` 완료, PRD `SERIES-001~013`와 API Contract §6 확인.
|
||||
- **시작 조건:** `P4-T2` 완료, PRD `SERIES-001~013`, `MOCK-001~009`와 API Contract §6 확인.
|
||||
- **완료 증거:** 체크박스 전체, 제공 계약 또는 제외 결정의 세 문서 일치, 상태/action inventory.
|
||||
- **범위 밖:** 계약 없는 genre/연결/순서 network 구현.
|
||||
|
||||
@@ -834,12 +938,13 @@ npm run build
|
||||
- [ ] 활성 Series가 50개를 넘을 때 전체를 누락 없이 읽는 방식과 누락 ID·동시 변경 충돌 오류를 기록한다.
|
||||
- [ ] 계약이 없는 연결·순서·genre 기능은 추측 구현하지 않고 제외/후속 여부를 문서에서 먼저 결정한다.
|
||||
- [ ] 목록·상세·form·연결·순서 화면의 상태/action inventory를 작성하고 Page는 route/query/policy 조합, feature component는 Series 규칙, shared component는 Phase 1 contract를 사용하도록 component map을 확정한다.
|
||||
- [ ] 제공 계약 범위만 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와 검증 기록.
|
||||
- **범위 밖:** Audio 연결·해제와 전체 순서 저장.
|
||||
|
||||
@@ -852,12 +957,13 @@ npm run build
|
||||
- [ ] genre 계약이 제공됐다면 이름 검색 후 `genreId`만 전송하는 Combobox를 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한다.
|
||||
- [ ] 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` 결정 기록.
|
||||
- **범위 밖:** 계약 없는 후보/전체 로딩/충돌 동작의 추정 구현.
|
||||
|
||||
@@ -869,12 +975,13 @@ npm run build
|
||||
- [ ] drag-and-drop과 동일한 결과를 keyboard·위/아래 button으로 만들 수 있는 test를 작성한다.
|
||||
- [ ] server의 누락 ID·동시 충돌 오류에서 기존 화면 순서를 보존하고 재조회/재시도 안내를 제공한다.
|
||||
- [ ] 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 기록.
|
||||
- **범위 밖:** 모바일 CRUD·연결·순서 mutation.
|
||||
|
||||
@@ -882,39 +989,40 @@ npm run build
|
||||
- [ ] desktop/tablet에서 전체 관리 흐름을 제공한다.
|
||||
- [ ] keyboard-only 요일·genre·연결·정렬, 320px 조회, 200% zoom, axe critical·serious 0건을 확인한다.
|
||||
|
||||
### Phase 4 Gate
|
||||
### Phase 5 Gate
|
||||
|
||||
**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 검증 기록.
|
||||
- **범위 밖:** 실패와 무관한 Community/FanTalk 구현.
|
||||
|
||||
```bash
|
||||
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 typecheck
|
||||
npm run lint
|
||||
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만으로 게시글 등록·조회·수정·고정·비활성화·첨부 재생을 완료한다.
|
||||
|
||||
**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 완료.
|
||||
- **완료 조건:** `P5-T1`~`P5-T4`, `P5-GATE` 완료. 오류·price는 제공 계약 또는 최소 규칙으로 종결.
|
||||
- **시작 조건:** `P2-GATE`와 `P4-T2` player integration 완료.
|
||||
- **완료 조건:** `P6-T1`~`P6-T4`, `P6-GATE` 완료. 오류·price는 제공 계약 또는 최소 규칙으로 종결.
|
||||
- **실행 순서:** 계약 확인 → 목록/Sheet → form/media → 반응형·접근성.
|
||||
|
||||
**요구사항:** `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에서 연결한다.
|
||||
|
||||
**주요 Files:**
|
||||
|
||||
@@ -928,23 +1036,24 @@ npm run build
|
||||
- Create: `src/features/community-posts/tests/{community-list,community-sheet}.test.tsx`
|
||||
- Create: `tests/e2e/community-post.spec.ts`
|
||||
|
||||
### Task 5.1 Phase 계약 확인
|
||||
### Task 6.1 Phase 계약 확인
|
||||
|
||||
**Goal 실행 `P5-T1`:** Community 오류·media·price 계약과 목록/Sheet component map을 확정한다.
|
||||
**Goal 실행 `P6-T1`:** Community 오류·media·price 계약, mock scenario와 목록/Sheet component map을 확정한다.
|
||||
|
||||
- **시작 조건:** `P1-T6`, `P3-T2` 완료, PRD `COMMUNITY-001~011`과 API Contract §7 확인.
|
||||
- **시작 조건:** `P2-GATE`, `P4-T2` 완료, PRD `COMMUNITY-001~011`, `MOCK-001~009`와 API Contract §7 확인.
|
||||
- **완료 증거:** 체크박스 전체, contract fixture와 상태/action inventory의 세 문서 일치.
|
||||
- **범위 밖:** price 상한·오류 key 추정과 Comments 구현.
|
||||
|
||||
- [ ] Community 오류 status/message key와 media upload 오류 fixture를 기록한다.
|
||||
- [ ] price 최대값이 제공되면 Audio와 같은 정책으로 갱신하고, 없으면 0 이상 정수만 유지한다.
|
||||
- [ ] 목록·Sheet·form/media의 상태/action inventory를 작성하고 Page는 collection query/policy 조합, feature component는 Community 규칙, shared component는 Phase 1 contract를 사용하도록 component map을 확정한다.
|
||||
- [ ] Community active list, Sheet, pin, media와 CRUD의 deterministic browser fixture 시나리오를 확정한다.
|
||||
|
||||
### Task 5.2 목록·collection Sheet
|
||||
### Task 6.2 목록·collection Sheet
|
||||
|
||||
**Goal 실행 `P5-T2`:** 전용 detail route/GET 없는 active 목록과 collection Sheet mutation 흐름을 완성한다.
|
||||
**Goal 실행 `P6-T2`:** 전용 detail route/GET 없는 active 목록과 collection Sheet mutation 흐름을 완성한다.
|
||||
|
||||
- **시작 조건:** `P5-T1` 완료.
|
||||
- **시작 조건:** `P6-T1` 완료.
|
||||
- **완료 증거:** 체크박스 전체, list/Sheet/router/cache/pin/deactivate test와 detail GET 0회 기록.
|
||||
- **범위 밖:** 댓글과 제공 계약에 없는 Community 검색.
|
||||
|
||||
@@ -955,12 +1064,13 @@ npm run build
|
||||
- [ ] 고정/해제 후 `isFixed/fixedAtUtc`를 server 값으로 표시한다.
|
||||
- [ ] soft delete 응답의 `isFixed=false`, `fixedAtUtc=null`을 contract test로 고정한다.
|
||||
- [ ] soft delete 성공 시 Sheet 종료, active-only 목록 재조회·항목 제거, 성공 toast를 확인한다.
|
||||
- [ ] mock mode도 전용 detail GET 없이 list store만으로 Sheet와 pin/deactivate 최종 UI를 갱신한다.
|
||||
|
||||
### Task 5.3 게시글 form·첨부 media
|
||||
### Task 6.3 게시글 form·첨부 media
|
||||
|
||||
**Goal 실행 `P5-T3`:** Community form, JPEG/PNG/GIF와 audio 첨부·재생 규칙을 완성한다.
|
||||
**Goal 실행 `P6-T3`:** Community form, JPEG/PNG/GIF와 audio 첨부·재생 규칙을 완성한다.
|
||||
|
||||
- **시작 조건:** `P5-T1`, `P5-T2` 완료.
|
||||
- **시작 조건:** `P6-T1`, `P6-T2` 완료.
|
||||
- **완료 증거:** 체크박스 전체, serializer/form/media/file-boundary/player test, `OQ-009` 결정 기록.
|
||||
- **범위 밖:** GIF 재인코딩, URL 갱신 전용 요청, Comments.
|
||||
|
||||
@@ -969,17 +1079,18 @@ npm run build
|
||||
- [ ] JPEG/PNG는 자유 ratio crop·최대 800px·no-upscale을 적용한다.
|
||||
- [ ] GIF는 Community에서만 허용하고 crop Dialog/canvas/re-encode 없이 원본 ratio·animation을 유지한다.
|
||||
- [ ] GIF 원본 width 800px은 허용하고 801px은 제출 전에 거부한다.
|
||||
- [ ] 첨부 Audio는 Phase 1의 공통 audio file policy와 `FileField`를 Phase 3과 동일하게 조합해 MP3/AAC/M4A, x-m4a, `1,024,000,000 bytes`, WAV 거부 규칙을 재사용한다.
|
||||
- [ ] 첨부 Audio는 Phase 1의 공통 audio file policy와 `FileField`를 Phase 4와 동일하게 조합해 MP3/AAC/M4A, x-m4a, `1,024,000,000 bytes`, WAV 거부 규칙을 재사용한다.
|
||||
- [ ] 첨부 Audio가 있으면 목록 Card/row와 Sheet에 공통 player를 렌더링한다.
|
||||
- [ ] media error가 detail/list refetch·URL 재발급·자동 play를 발생시키지 않는다.
|
||||
- [ ] 사용자 새로고침이나 mutation cache invalidation으로 목록이 정상 재조회된 때만 새 `audioSignedUrl`을 사용한다.
|
||||
- [ ] Community Sheet/form을 실제로 작성한 뒤 `OQ-009`의 `content` 상한 필요성을 판단하고, 구현 전 결정 문서를 갱신하거나 “상한 추가 없음”으로 종결한다.
|
||||
- [ ] mock handler가 multipart contract를 검증하고 local preview media asset으로 create/update/play 최종 UI를 재현한다.
|
||||
|
||||
### Task 5.4 Community 반응형·접근성
|
||||
### Task 6.4 Community 반응형·접근성
|
||||
|
||||
**Goal 실행 `P5-T4`:** Community viewport capability와 Sheet/media/form 접근성을 검증한다.
|
||||
**Goal 실행 `P6-T4`:** Community viewport capability와 Sheet/media/form 접근성을 검증한다.
|
||||
|
||||
- **시작 조건:** `P5-T2`, `P5-T3`의 활성 범위 완료.
|
||||
- **시작 조건:** `P6-T2`, `P6-T3`의 활성 범위 완료.
|
||||
- **완료 증거:** 체크박스 전체, focus trap/복귀·320px·keyboard·200% zoom·axe E2E 기록.
|
||||
- **범위 밖:** 모바일 등록·수정·고정·비활성화.
|
||||
|
||||
@@ -987,34 +1098,35 @@ npm run build
|
||||
- [ ] desktop/tablet에는 전체 관리 흐름을 제공한다.
|
||||
- [ ] Sheet focus trap/복귀, keyboard media/form, 320px overflow, 200% zoom, axe critical·serious 0건을 확인한다.
|
||||
|
||||
### Phase 5 Gate
|
||||
### Phase 6 Gate
|
||||
|
||||
**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 검증 기록.
|
||||
- **범위 밖:** 실패와 무관한 FanTalk/Comments 구현.
|
||||
|
||||
```bash
|
||||
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 typecheck
|
||||
npm run lint
|
||||
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를 최신순·답변 상태로 조회하고 답변을 한 번 작성한 뒤 기존 답변만 수정한다.
|
||||
|
||||
**Phase Goal `P6`:** Task 6.1 → 6.3과 Phase 6 Gate로 FanTalk 조회·단일 답변·수정 slice를 완성한다.
|
||||
**Phase Goal `P7`:** Task 7.1 → 7.3과 Phase 7 Gate로 FanTalk 조회·단일 답변·수정 slice를 완성한다.
|
||||
|
||||
- **시작 조건:** `P2-T2` workspace core 완료.
|
||||
- **완료 조건:** 핵심 계약이 제공되면 `P6-T1`~`P6-T3`, `P6-GATE` 완료. 미제공이면 Phase 제외/후속 결정 문서화로 종결.
|
||||
- **시작 조건:** `P3-T2` workspace core와 `P2-GATE` 완료.
|
||||
- **완료 조건:** 핵심 계약이 제공되면 `P7-T1`~`P7-T3`, `P7-GATE` 완료. 미제공이면 Phase 제외/후속 결정 문서화로 종결.
|
||||
- **실행 순서:** 계약 확인 → 목록/답변 → 반응형·접근성.
|
||||
|
||||
**요구사항:** `FANTALK-001~008`, PRD `9`의 FanTalk 범위.
|
||||
@@ -1033,11 +1145,11 @@ npm run build
|
||||
- Create: `tests/e2e/fan-talk.spec.ts`
|
||||
- Modify: `src/app/router.tsx`
|
||||
|
||||
### Task 6.1 Phase 계약 확인
|
||||
### Task 7.1 Phase 계약 확인
|
||||
|
||||
**Goal 실행 `P6-T1`:** FanTalk 목록·상세·수정·유일성·오류 계약과 component map을 확정한다.
|
||||
**Goal 실행 `P7-T1`:** FanTalk 목록·상세·수정·유일성·오류 계약, mock 가능 범위와 component map을 확정한다.
|
||||
|
||||
- **시작 조건:** `P2-T2` 완료, PRD `FANTALK-001~008`와 API Contract §8~9 확인.
|
||||
- **시작 조건:** `P3-T2`, `P2-GATE` 완료, PRD `FANTALK-001~008`, `MOCK-001~009`와 API Contract §8~9 확인.
|
||||
- **완료 증거:** 체크박스 전체, 제공 계약 또는 Phase 제외/후속 결정의 세 문서 일치.
|
||||
- **범위 밖:** 임시 endpoint·placeholder DTO·production mock adapter.
|
||||
|
||||
@@ -1045,12 +1157,13 @@ npm run build
|
||||
- [ ] 답변 1개를 server가 원자적으로 강제하는 방식과 중복 생성 비2xx status/message key를 기록한다.
|
||||
- [ ] 계약이 없으면 임시 endpoint·placeholder DTO·mock production adapter를 만들지 않고 Phase 제외/후속 결정을 문서화한다.
|
||||
- [ ] 목록·상세·reply form의 상태/action inventory를 작성하고 Page는 route/query/policy 조합, feature component는 FanTalk 규칙, shared component는 Phase 1 contract를 사용하도록 component map을 확정한다.
|
||||
- [ ] 목록·상세·수정·유일성 계약이 모두 제공된 뒤에만 browser fixture를 만들고, 현재 제공된 POST만으로 최종 FanTalk mock UI를 추정하지 않는다.
|
||||
|
||||
### Task 6.2 목록·답변 생성·수정
|
||||
### Task 7.2 목록·답변 생성·수정
|
||||
|
||||
**Goal 실행 `P6-T2`:** 최신순/filter 목록과 답변 1회 생성·기존 답변 수정 흐름을 완성한다.
|
||||
**Goal 실행 `P7-T2`:** 최신순/filter 목록과 답변 1회 생성·기존 답변 수정 흐름을 완성한다.
|
||||
|
||||
- **시작 조건:** `P6-T1`에서 핵심 계약 제공 확인.
|
||||
- **시작 조건:** `P7-T1`에서 핵심 계약 제공 확인.
|
||||
- **완료 증거:** 체크박스 전체, list/detail/reply contract·UI test, 중복 제출/오류 복구, `OQ-009` 결정 기록.
|
||||
- **범위 밖:** 답변 삭제·두 번째 답변과 계약 없는 network 동작.
|
||||
|
||||
@@ -1062,12 +1175,13 @@ npm run build
|
||||
- [ ] server 중복 오류를 받으면 최신 detail을 재조회해 edit 상태로 전환하고 status/key를 추정 분기하지 않는다.
|
||||
- [ ] 저장 중 중복 제출 차단, visible label, 오류 연결, 성공 live feedback을 test한다.
|
||||
- [ ] FanTalk reply form을 실제로 작성한 뒤 `OQ-009`의 `content` 상한 필요성을 판단하고, 구현 전 결정 문서를 갱신하거나 “상한 추가 없음”으로 종결한다.
|
||||
- [ ] 계약 제공 후 mock store로 미답변 → 답변 생성 → 수정과 중복 오류의 최종 UI E2E를 작성한다.
|
||||
|
||||
### Task 6.3 FanTalk 반응형·접근성
|
||||
### Task 7.3 FanTalk 반응형·접근성
|
||||
|
||||
**Goal 실행 `P6-T3`:** 모든 viewport의 FanTalk 응대 capability와 접근성을 검증한다.
|
||||
**Goal 실행 `P7-T3`:** 모든 viewport의 FanTalk 응대 capability와 접근성을 검증한다.
|
||||
|
||||
- **시작 조건:** `P6-T2` 완료.
|
||||
- **시작 조건:** `P7-T2` 완료.
|
||||
- **완료 증거:** 체크박스 전체, 320px keyboard viewport·keyboard-only·200% zoom·axe E2E 기록.
|
||||
- **범위 밖:** viewport별 기능 축소와 답변 삭제.
|
||||
|
||||
@@ -1075,34 +1189,35 @@ npm run build
|
||||
- [ ] 320px에서 keyboard가 reply input/submit을 가리지 않는 E2E를 작성한다.
|
||||
- [ ] keyboard-only filter/detail/create/edit, 200% zoom, axe critical·serious 0건을 확인한다.
|
||||
|
||||
### Phase 6 Gate
|
||||
### Phase 7 Gate
|
||||
|
||||
**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 제외 결정의 검증 기록.
|
||||
- **범위 밖:** 계약 미제공 상태에서 network integration 완료 주장.
|
||||
|
||||
```bash
|
||||
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 typecheck
|
||||
npm run lint
|
||||
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 권한을 일관되게 적용한다.
|
||||
|
||||
**Phase Goal `P7`:** Task 7.1 → 7.4와 Phase 7 Gate로 두 target의 2단계 Comments slice를 완성한다.
|
||||
**Phase Goal `P8`:** Task 8.1 → 8.4와 Phase 8 Gate로 두 target의 2단계 Comments slice를 완성한다.
|
||||
|
||||
- **시작 조건:** `P3-T2` Audio detail과 `P5-T2` Community Sheet 완료.
|
||||
- **완료 조건:** 핵심 계약이 제공되면 `P7-T1`~`P7-T4`, `P7-GATE` 완료. 미제공이면 Phase 제외/후속 결정 문서화로 종결.
|
||||
- **시작 조건:** `P4-T2` Audio detail, `P6-T2` Community Sheet와 `P2-GATE` 완료.
|
||||
- **완료 조건:** 핵심 계약이 제공되면 `P8-T1`~`P8-T4`, `P8-GATE` 완료. 미제공이면 Phase 제외/후속 결정 문서화로 종결.
|
||||
- **실행 순서:** 계약 확인 → target/thread → 권한 action → 반응형·접근성.
|
||||
|
||||
**요구사항:** `COMMENT-001~006`, PRD `9`의 Comments 범위.
|
||||
@@ -1120,11 +1235,11 @@ npm run build
|
||||
- Create: `tests/e2e/comments.spec.ts`
|
||||
- Modify: `AudioContentDetailPage.tsx`, `CommunityPostSheet.tsx`
|
||||
|
||||
### Task 7.1 Phase 계약 확인
|
||||
### Task 8.1 Phase 계약 확인
|
||||
|
||||
**Goal 실행 `P7-T1`:** 두 댓글 target의 CRUD·2단계·권한 오류 계약과 component map을 확정한다.
|
||||
**Goal 실행 `P8-T1`:** 두 댓글 target의 CRUD·2단계·권한 오류 계약, mock 가능 범위와 component map을 확정한다.
|
||||
|
||||
- **시작 조건:** `P3-T2`, `P5-T2` 완료, PRD `COMMENT-001~006`과 API Contract §9 확인.
|
||||
- **시작 조건:** `P4-T2`, `P6-T2`, `P2-GATE` 완료, PRD `COMMENT-001~006`, `MOCK-001~009`와 API Contract §9 확인.
|
||||
- **완료 증거:** 체크박스 전체, 제공 계약 또는 Phase 제외/후속 결정의 세 문서 일치.
|
||||
- **범위 밖:** endpoint 이름 추정과 client-only permission 완료 주장.
|
||||
|
||||
@@ -1132,12 +1247,13 @@ npm run build
|
||||
- [ ] root/direct reply 정확히 2단계인 server rule과 fan content 삭제 권한 오류 status/message key를 기록한다.
|
||||
- [ ] 계약이 없으면 target endpoint를 이름만 보고 추정하거나 client-only permission을 완료로 간주하지 않는다.
|
||||
- [ ] Audio detail·Community Sheet 진입별 thread/form/action inventory를 작성하고 host Page/Sheet는 target·query 조합, Comments component는 thread·permission 규칙, shared component는 Phase 1 contract를 사용하도록 component map을 확정한다.
|
||||
- [ ] target별 CRUD·2단계·권한 오류 계약이 제공된 뒤에만 browser fixture를 만들고 현재 미제공 계약을 mock DTO로 추정하지 않는다.
|
||||
|
||||
### Task 7.2 target adapter·2단계 thread
|
||||
### Task 8.2 target adapter·2단계 thread
|
||||
|
||||
**Goal 실행 `P7-T2`:** Audio/Community target adapter와 정확히 2단계인 comment thread 조회를 완성한다.
|
||||
**Goal 실행 `P8-T2`:** Audio/Community target adapter와 정확히 2단계인 comment thread 조회를 완성한다.
|
||||
|
||||
- **시작 조건:** `P7-T1`에서 핵심 계약 제공 확인.
|
||||
- **시작 조건:** `P8-T1`에서 핵심 계약 제공 확인.
|
||||
- **완료 증거:** 체크박스 전체, target contract/thread/state/page test와 Community 상태 보존 기록.
|
||||
- **범위 밖:** 작성자별 mutation action.
|
||||
|
||||
@@ -1147,11 +1263,11 @@ npm run build
|
||||
- [ ] root와 direct reply만 렌더링하고 reply에는 reply action이 없음을 test한다.
|
||||
- [ ] long content, loading·empty·error·retry, page 갱신을 양 target에서 test한다.
|
||||
|
||||
### Task 7.3 작성자별 action
|
||||
### Task 8.3 작성자별 action
|
||||
|
||||
**Goal 실행 `P7-T3`:** AI Character와 fan 작성자별 수정·soft delete 권한을 일관되게 적용한다.
|
||||
**Goal 실행 `P8-T3`:** AI Character와 fan 작성자별 수정·soft delete 권한을 일관되게 적용한다.
|
||||
|
||||
- **시작 조건:** `P7-T1`, `P7-T2` 완료.
|
||||
- **시작 조건:** `P8-T1`, `P8-T2` 완료.
|
||||
- **완료 증거:** 체크박스 전체, permission/mutation/session/read-only test, `OQ-009` 결정 기록.
|
||||
- **범위 밖:** fan edit와 reply의 reply.
|
||||
|
||||
@@ -1162,12 +1278,13 @@ npm run build
|
||||
- [ ] Character workspace read-only 정책이 모든 comment mutation도 차단하는 test를 작성한다.
|
||||
- [ ] 중복 제출, server permission 오류, session 401/403이 공통 정책을 따르는지 test한다.
|
||||
- [ ] Comment thread/form을 실제로 작성한 뒤 `OQ-009`의 `content` 상한 필요성을 판단하고, 구현 전 결정 문서를 갱신하거나 “상한 추가 없음”으로 종결한다.
|
||||
- [ ] 계약 제공 후 mock store로 양 target의 root/reply CRUD와 작성자별 권한 오류 최종 UI E2E를 작성한다.
|
||||
|
||||
### Task 7.4 Comments 반응형·접근성
|
||||
### Task 8.4 Comments 반응형·접근성
|
||||
|
||||
**Goal 실행 `P7-T4`:** 모든 viewport의 Comments CRUD capability와 thread/form/dialog 접근성을 검증한다.
|
||||
**Goal 실행 `P8-T4`:** 모든 viewport의 Comments CRUD capability와 thread/form/dialog 접근성을 검증한다.
|
||||
|
||||
- **시작 조건:** `P7-T2`, `P7-T3` 완료.
|
||||
- **시작 조건:** `P8-T2`, `P8-T3` 완료.
|
||||
- **완료 증거:** 체크박스 전체, 320px·keyboard-only·focus 복귀·200% zoom·axe E2E 기록.
|
||||
- **범위 밖:** 모바일 기능 축소.
|
||||
|
||||
@@ -1175,34 +1292,35 @@ npm run build
|
||||
- [ ] 320px에서 긴 댓글, reply indentation, action menu, keyboard 입력이 overflow하지 않는 E2E를 작성한다.
|
||||
- [ ] keyboard-only root/reply 작성·수정·delete dialog, focus 복귀, 200% zoom, axe critical·serious 0건을 확인한다.
|
||||
|
||||
### Phase 7 Gate
|
||||
### Phase 8 Gate
|
||||
|
||||
**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 제외 결정의 검증 기록.
|
||||
- **범위 밖:** 계약 미제공 상태에서 network integration 완료 주장.
|
||||
|
||||
```bash
|
||||
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 typecheck
|
||||
npm run lint
|
||||
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, 보안, 반응형, 접근성 기준을 만족한다는 최신 증거를 남긴다.
|
||||
|
||||
**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` 완료 또는 명시적 제외 결정.
|
||||
- **완료 조건:** `P8-T1`~`P8-T3`, `P8-GATE` 완료, 전체 자동 Gate 0 failure/0 error와 수동 검증 기록.
|
||||
- **시작 조건:** 활성 범위의 `P0-GATE`~`P8-GATE` 완료 또는 명시적 제외 결정.
|
||||
- **완료 조건:** `P9-T1`~`P9-T3`, `P9-GATE` 완료, mock/server 전체 자동 Gate 0 failure/0 error와 수동 검증 기록.
|
||||
- **실행 순서:** 교차 journey/오류 → 반응형/접근성/보안 → 문서/품질 → 전체 Gate.
|
||||
|
||||
**주요 Files:**
|
||||
@@ -1211,11 +1329,11 @@ npm run build
|
||||
- Modify: `README.md`
|
||||
- Modify: `docs/20260725_AI캐릭터관리자웹/{prd.md,api-contract.md,plan-task.md}` only when actual implementation decision differs.
|
||||
|
||||
### Task 8.1 교차 journey·오류 회귀
|
||||
### Task 9.1 교차 journey·오류 회귀
|
||||
|
||||
**Goal 실행 `P8-T1`:** 활성 도메인의 교차 journey, 오류 매핑과 serializer/security 불변식을 회귀 검증한다.
|
||||
**Goal 실행 `P9-T1`:** 활성 도메인의 mock/server 교차 journey, 오류 매핑과 serializer/security 불변식을 회귀 검증한다.
|
||||
|
||||
- **시작 조건:** 활성 범위의 Phase 0~7 Gate 완료 또는 제외 결정.
|
||||
- **시작 조건:** 활성 범위의 Phase 0~8 Gate 완료 또는 제외 결정.
|
||||
- **완료 증거:** 체크박스 전체, resource-workflows/error-mapping E2E와 request 0회·serializer fixture 기록.
|
||||
- **범위 밖:** 새 기능과 계약 미제공 제외 범위의 가짜 journey.
|
||||
|
||||
@@ -1225,12 +1343,14 @@ npm run build
|
||||
- [ ] inactive Character workspace에서 모든 하위 mutation request가 0건인지 검증한다.
|
||||
- [ ] media error로 Audio/Community GET·URL 재발급·자동 `play()`가 발생하지 않는지 검증한다.
|
||||
- [ ] 생성·일반 수정·soft delete serializer 불변식을 모든 도메인 fixture에서 다시 검증한다.
|
||||
- [ ] 모든 활성 도메인의 mock handler가 정규화 endpoint·DTO를 사용하고 실제 backend request 0건으로 최종 UI journey를 재현하는지 검증한다.
|
||||
- [ ] server mode의 404·network error가 mock으로 전환되지 않고 실제 오류 UI와 연동 대기 기록으로 남는지 검증한다.
|
||||
|
||||
### Task 8.2 반응형·접근성·보안 회귀
|
||||
### Task 9.2 반응형·접근성·보안 회귀
|
||||
|
||||
**Goal 실행 `P8-T2`:** 지원 viewport/browser의 capability, 접근성과 민감정보 비기록을 전역 검증한다.
|
||||
**Goal 실행 `P9-T2`:** 지원 viewport/browser의 capability, 접근성과 민감정보 비기록을 mock/server 양 mode에서 검증한다.
|
||||
|
||||
- **시작 조건:** `P8-T1` 완료.
|
||||
- **시작 조건:** `P9-T1` 완료.
|
||||
- **완료 증거:** 체크박스 전체, table-driven E2E·axe·수동 browser/keyboard/zoom/security·UX 검색 기록.
|
||||
- **범위 밖:** 다크 모드 구현과 외부 WCAG 인증.
|
||||
|
||||
@@ -1243,12 +1363,13 @@ npm run build
|
||||
- [ ] JWT, password, signed URL, file body가 log·storage·분석 event에 남지 않는지 검증한다.
|
||||
- [ ] 각 Page가 승인된 component map대로 route/query/permission과 component 조합만 담당하고, domain 상호작용이 feature/shared component test로 분리됐는지 review한다.
|
||||
- [ ] PRD `10.9`의 UX 검증 검색을 다시 실행하고 채택·제외 결과를 기록한다.
|
||||
- [ ] mock mode banner가 모든 viewport에서 핵심 UI를 가리지 않고 실제 server와 혼동되지 않는지 확인한다.
|
||||
|
||||
### Task 8.3 문서·품질 Gate
|
||||
### Task 9.3 문서·품질 Gate
|
||||
|
||||
**Goal 실행 `P8-T3`:** 요구사항 추적, 외부 의존·Open Question, README와 검증 기록을 실제 구현에 맞춘다.
|
||||
**Goal 실행 `P9-T3`:** 요구사항 추적, 외부 의존·Open Question, mock/server 상태, README와 검증 기록을 실제 구현에 맞춘다.
|
||||
|
||||
- **시작 조건:** `P8-T1`, `P8-T2` 완료.
|
||||
- **시작 조건:** `P9-T1`, `P9-T2` 완료.
|
||||
- **완료 증거:** 체크박스 전체, PRD 수용 기준별 증거 연결, 독립 code review 수정과 관련 Gate 재실행 기록.
|
||||
- **범위 밖:** 결정되지 않은 계약을 문서상 확정하는 행위.
|
||||
|
||||
@@ -1260,12 +1381,13 @@ npm run build
|
||||
- [ ] README에 install, env, run, test, build, 지원 브라우저, 알려진 backend 제약을 기록한다.
|
||||
- [ ] plan 하단 검증 기록에 무엇을/왜/어떻게와 실제 명령·성공/실패/불가 사유를 누적한다.
|
||||
- [ ] 별도 code review를 받고 지적사항 수정 후 관련 Phase Gate와 전체 Gate를 다시 실행한다.
|
||||
- [ ] 각 도메인의 `UI 확인 완료(mock)`와 `실제 서버 연동 완료(server)`가 Progress·추적표·알려진 제약에서 일치하는지 확인한다.
|
||||
|
||||
### Phase 8 Gate
|
||||
### Phase 9 Gate
|
||||
|
||||
**Goal 실행 `P8-GATE`:** 활성 릴리스 전체의 install·type·lint·unit·E2E·build·금지 패턴을 최종 판정한다.
|
||||
**Goal 실행 `P9-GATE`:** 활성 릴리스 전체의 install·type·lint·unit·mock/server E2E·build·금지 패턴을 최종 판정한다.
|
||||
|
||||
- **시작 조건:** `P8-T1`~`P8-T3` 완료.
|
||||
- **시작 조건:** `P9-T1`~`P9-T3` 완료.
|
||||
- **완료 증거:** 아래 명령이 0 failure/0 error이고 Expected 및 수동 검증 결과가 최종 검증 기록에 누적됨.
|
||||
- **범위 밖:** Gate 통과를 위한 test 삭제·완화, production placeholder, 계약 추정.
|
||||
|
||||
@@ -1285,6 +1407,7 @@ npm ci
|
||||
npm run typecheck
|
||||
npm run lint
|
||||
npm run test:run
|
||||
npm run e2e:mock
|
||||
npm run e2e
|
||||
npm run build
|
||||
assert_no_match 'TODO|TBD|FIXME' src tests
|
||||
@@ -1292,7 +1415,7 @@ assert_no_match "externalCharacterId|SUNDAY|MONDAY|TUESDAY|WEDNESDAY|THURSDAY|FR
|
||||
--glob '!**/*.test.*' --glob '!**/*.spec.*' --glob '!**/__tests__/**'
|
||||
```
|
||||
|
||||
**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건이다.
|
||||
|
||||
## 5. 요구사항 추적표
|
||||
|
||||
@@ -1300,21 +1423,25 @@ assert_no_match "externalCharacterId|SUNDAY|MONDAY|TUESDAY|WEDNESDAY|THURSDAY|FR
|
||||
|---:|---|---|
|
||||
| 0 | React+TypeScript+Vite, 지원 브라우저 기반 | `src/app/App.test.tsx`, `tests/e2e/smoke.spec.ts` |
|
||||
| 1 | `AUTH-001~013`, `UX-001~002`, `FILE`의 domain-neutral component mechanics, §7, §10 공통, §11.1~11.2, §12 | `src/shared`, `src/features/auth`, `tests/e2e/auth.spec.ts` |
|
||||
| 2 | `CHAR-001~014`, Character 관련 `FILE`, §7, §9 | `src/features/characters`, `tests/e2e/character-workspace.spec.ts` |
|
||||
| 3 | `AUDIO-001~028`, Audio 관련 `FILE`, §9 | `src/features/audio-contents`, `tests/e2e/audio-content.spec.ts` |
|
||||
| 4 | `SERIES-001~013`, Series 관련 `FILE`, §9 | `src/features/series`, `tests/e2e/series.spec.ts` |
|
||||
| 5 | `COMMUNITY-001~011`, Community 관련 `FILE`, §9 | `src/features/community-posts`, `tests/e2e/community-post.spec.ts` |
|
||||
| 6 | `FANTALK-001~008`, §9 | `src/features/fan-talks`, `tests/e2e/fan-talk.spec.ts` |
|
||||
| 7 | `COMMENT-001~006`, §9 | `src/features/comments`, `tests/e2e/comments.spec.ts` |
|
||||
| 8 | §9~10, §12~14, 활성 범위 전체 | 전체 unit/integration/E2E/build |
|
||||
| 2 | `MOCK-001~009`, §11.1~11.2, §12~13 | `src/shared/mocks`, `tests/e2e/mock-preview-shell.spec.ts` |
|
||||
| 3 | `CHAR-001~014`, Character 관련 `FILE`, `MOCK`, §7, §9 | `src/features/characters`, `tests/e2e/character-workspace.spec.ts` |
|
||||
| 4 | `AUDIO-001~028`, Audio 관련 `FILE`, `MOCK`, §9 | `src/features/audio-contents`, `tests/e2e/audio-content.spec.ts` |
|
||||
| 5 | `SERIES-001~013`, Series 관련 `FILE`, `MOCK`, §9 | `src/features/series`, `tests/e2e/series.spec.ts` |
|
||||
| 6 | `COMMUNITY-001~011`, Community 관련 `FILE`, `MOCK`, §9 | `src/features/community-posts`, `tests/e2e/community-post.spec.ts` |
|
||||
| 7 | `FANTALK-001~008`, `MOCK`, §9 | `src/features/fan-talks`, `tests/e2e/fan-talk.spec.ts` |
|
||||
| 8 | `COMMENT-001~006`, `MOCK`, §9 | `src/features/comments`, `tests/e2e/comments.spec.ts` |
|
||||
| 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. 구현 완료 정의
|
||||
|
||||
- [ ] Phase 0~7의 활성 범위 Gate와 Phase 8 전체 Gate가 최신 실행에서 통과한다.
|
||||
- [ ] Phase 0~8의 활성 범위 Gate와 Phase 9 전체 Gate가 최신 실행에서 통과한다.
|
||||
- [ ] 모든 **확정** 요구사항이 구현, 명시적 non-goal, 또는 결정 기록이 있는 후속 범위 중 하나로 추적된다.
|
||||
- [ ] 외부 의존을 추정 endpoint·placeholder DTO·임시 production mock으로 우회하지 않았다.
|
||||
- [ ] 제공 계약 범위는 `dev:mock`에서 최종 UI를 확인할 수 있고, 계약 미제공 범위는 fixture로 추정하지 않았다.
|
||||
- [ ] 각 도메인의 `UI 확인 완료(mock)`와 `실제 서버 연동 완료(server)` 상태와 증거가 분리돼 있다.
|
||||
- [ ] server mode의 404·network error가 mock으로 자동 fallback되지 않고 production build에서 browser mock이 활성화되지 않는다.
|
||||
- [ ] 생성·일반 수정·soft delete payload와 enum 보정 contract test가 통과한다.
|
||||
- [ ] desktop/tablet/mobile 기능 matrix가 route와 action policy 양쪽에서 일치한다.
|
||||
- [ ] 파일 MIME·크기·crop·no-upscale·GIF·오디오 경계 test가 통과한다.
|
||||
@@ -1486,3 +1613,16 @@ assert_no_match "externalCharacterId|SUNDAY|MONDAY|TUESDAY|WEDNESDAY|THURSDAY|FR
|
||||
- PRD `AUDIO-027~028`, API Contract §5.0/§5.3, Phase 3 요구사항·contract/form checklist 대조 — `themeId`와 공통 테마 목록 계약이 일치함을 확인.
|
||||
- 애플리케이션 test/build — 문서와 goal 실행 계약만 변경해 실행하지 않음.
|
||||
- 남은 항목: Phase 2 이후 구현과 각 도메인의 backend 제공 대기 계약.
|
||||
|
||||
### 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를 만들지 않는다.
|
||||
|
||||
Reference in New Issue
Block a user