feat(ai-character): 커뮤니티 댓글 첫 답글 작성 지원
This commit is contained in:
227
docs/20260806_커뮤니티댓글답글/prd.md
Normal file
227
docs/20260806_커뮤니티댓글답글/prd.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# 커뮤니티 댓글 직접 답글 PRD
|
||||
|
||||
## 문서 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 문서 상태 | 구현 기준 확정 |
|
||||
| 작성일 | 2026-08-06 |
|
||||
| 최종 수정일 | 2026-08-06 |
|
||||
| 대상 기능 | 커뮤니티 게시글 댓글의 직접 답글 작성 진입 |
|
||||
| 작성자·결정권자 | Codex 작성, 사용자 결정 |
|
||||
| 상위 제품 기준 | [AI 캐릭터 관리자 웹 PRD](../20260725_AI캐릭터관리자웹/prd.md) |
|
||||
| 선행 기능 기준 | [오디오 콘텐츠 댓글 답글 PRD](../20260805_오디오콘텐츠댓글답글/prd.md) |
|
||||
| 관련 API Contract | [api-contract.md](./api-contract.md) |
|
||||
| 관련 구현 계획 | [plan-task.md](./plan-task.md) |
|
||||
| 관련 review | [Phase 1 커뮤니티 댓글 직접 답글 리뷰](./reviews/phase1-community-comment-replies.md) |
|
||||
|
||||
### 요구사항 상태
|
||||
|
||||
| 상태 | 의미 |
|
||||
|---|---|
|
||||
| 확정 | 구현과 검증 기준으로 사용한다. |
|
||||
| 미결 | 제품 결정 전에는 구현하지 않는다. |
|
||||
| 외부 의존 | 외부 계약이 제공될 때까지 영향 범위를 구현 완료로 표시하지 않는다. |
|
||||
| 제외 | 현재 기능 범위에 포함하지 않는다. |
|
||||
|
||||
## 1. Overview
|
||||
|
||||
활성 AI 캐릭터의 커뮤니티 게시글 원댓글에 직접 답글을 작성할 수 있게 한다.
|
||||
원댓글 아래에는 여러 개의 직접 답글을 추가할 수 있지만, 답글에 다시 답글을
|
||||
다는 3단계 구조는 허용하지 않는다. 기존 오디오 콘텐츠 댓글과 같은 진입 UI,
|
||||
답글 영역, 작성 form과 mutation 상태를 재사용한다.
|
||||
|
||||
## 2. Problem Statement
|
||||
|
||||
커뮤니티 답글 조회·작성 API와 UI는 이미 구현돼 있어 답글이 하나 이상인
|
||||
원댓글에는 추가 답글을 작성할 수 있다. 그러나 `replyCount=0`인 원댓글에는
|
||||
답글 영역을 여는 action이 없어 첫 답글을 작성할 수 없다.
|
||||
|
||||
문제를 해결했다는 판단은 답글 0개인 활성 커뮤니티 원댓글에서 `답글 작성`을
|
||||
눌러 첫 답글을 등록하고, 같은 원댓글에 여러 직접 답글을 계속 추가할 수 있는지로
|
||||
한다.
|
||||
|
||||
## 3. Goals
|
||||
|
||||
### 3.1 제품 목표
|
||||
|
||||
- 활성 커뮤니티 게시글의 모든 원댓글에 첫 답글을 작성할 수 있다.
|
||||
- 하나의 원댓글 아래 여러 직접 답글을 작성·조회할 수 있다.
|
||||
- 원댓글과 직접 답글로 끝나는 기존 2단계 댓글 구조를 유지한다.
|
||||
|
||||
### 3.2 UX 목표
|
||||
|
||||
- 답글이 0개인 원댓글에는 `답글 작성`이라는 명확한 진입점을 표시한다.
|
||||
- 버튼을 누르면 기존 답글 영역과 작성 form을 펼친다.
|
||||
- 기존 답글이 있는 원댓글은 `답글 보기`로 같은 영역을 열고 추가 답글을 작성한다.
|
||||
- 기존 loading, 오류, 전송 중, 실패 후 초안 보존 동작을 유지한다.
|
||||
|
||||
## 4. Non-Goals
|
||||
|
||||
- 답글의 답글을 포함한 3단계 이상의 댓글 구조
|
||||
- 답글 form 상시 노출
|
||||
- 새 endpoint, DTO, 상태관리, 컴포넌트 또는 UI dependency 추가
|
||||
- 오디오 콘텐츠 댓글 동작이나 payload 정책 변경
|
||||
- 기존 답글 수정·삭제·pagination 정책 변경
|
||||
- optimistic update 또는 답글 전체 선조회
|
||||
|
||||
## 5. Target Users and Permissions
|
||||
|
||||
| 사용자 | 목표 | 주요 작업 | 사용 환경 |
|
||||
|---|---|---|---|
|
||||
| ADMIN | AI 캐릭터 명의로 커뮤니티 원댓글에 직접 답글 작성 | 답글 영역 열기, 작성, 재시도 | desktop, tablet, mobile |
|
||||
|
||||
- 인증과 ADMIN 권한은 상위 제품 기준을 따른다.
|
||||
- 활성 AI 캐릭터 workspace에서만 답글 작성 control을 제공한다.
|
||||
- 비활성 AI 캐릭터 workspace는 기존처럼 조회 전용이다.
|
||||
- 원댓글 작성자가 팬인지 AI 캐릭터인지와 관계없이 답글을 작성할 수 있다.
|
||||
|
||||
## 6. 핵심 사용자 흐름
|
||||
|
||||
1. 관리자가 활성 AI 캐릭터의 커뮤니티 게시글 목록에 진입한다.
|
||||
2. 게시글 Sheet를 열고 답글이 0개인 원댓글에서 `답글 작성`을 누른다.
|
||||
3. UI가 해당 원댓글의 직접 답글 GET을 실행하고 답글 영역과 작성 form을 표시한다.
|
||||
4. 관리자가 내용을 입력해 등록한다.
|
||||
5. 기존 커뮤니티 댓글 POST에 원댓글 ID를 `parentId`로 보내고 성공 후 원댓글·열린 답글 목록을 재조회한다.
|
||||
6. 관리자는 같은 form으로 동일 원댓글에 추가 직접 답글을 작성할 수 있다.
|
||||
7. 실패하면 오류를 표시하고 입력 초안을 유지해 재시도할 수 있다.
|
||||
|
||||
## 7. 정보 구조와 라우팅
|
||||
|
||||
```text
|
||||
/ai-characters/:characterId/community-posts
|
||||
└─ 커뮤니티 게시글 Sheet
|
||||
└─ 댓글 관리
|
||||
└─ 원댓글
|
||||
└─ 직접 답글 목록 및 작성 form
|
||||
```
|
||||
|
||||
- 새 route와 query parameter를 추가하지 않는다.
|
||||
- 기존 `CommunityPostSheet`의 `CommentThread` 안에서만 동작한다.
|
||||
- 답글 pagination 상태는 기존 component의 로컬 상태를 사용한다.
|
||||
|
||||
## 8. 기능 요구사항
|
||||
|
||||
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|
||||
|---|---|---|---|---|
|
||||
| `CCR-001` | 확정 | 활성 Community target의 답글 0개 원댓글에 `답글 작성` 버튼을 표시한다. | `replyCount=0`, `canMutate=true`인 Community root에서 버튼을 찾을 수 있다. | contract 불필요, `P1-T1` |
|
||||
| `CCR-002` | 확정 | `답글 작성`을 누르면 선택한 원댓글의 기존 직접 답글 영역과 작성 form을 연다. | 버튼 클릭 뒤 해당 원댓글 이름과 연결된 답글 region·textarea·등록 버튼이 표시되고 page 0 GET을 한 번 요청한다. | 답글 GET, `P1-T1` |
|
||||
| `CCR-003` | 확정 | 첫 답글과 후속 직접 답글은 기존 Community 댓글 POST를 사용한다. | body가 trim된 `comment`, 원댓글 ID `parentId`, `isSecret=false`를 포함하고 `languageCode`는 보내지 않는다. | 댓글 POST, `P1-T1` |
|
||||
| `CCR-004` | 확정 | 하나의 원댓글에는 여러 직접 답글을 추가할 수 있다. | 답글 등록 성공 후 form을 다시 사용할 수 있고 원댓글·현재 답글 page를 재조회해 추가된 답글을 표시한다. | 답글 GET·댓글 POST, `P1-T1`, `P1-GATE` |
|
||||
| `CCR-005` | 확정 | 댓글 구조는 원댓글과 직접 답글의 2단계로 제한한다. | reply row에는 답글 action이 없고 답글 ID를 `parentId`로 보내는 작성 경로가 없다. | 댓글 POST, `P1-T1` |
|
||||
| `CCR-006` | 확정 | 기존 권한과 mutation 상태를 유지한다. | `canMutate=false`이면 첫 답글 작성 진입과 form이 없고, pending 중 중복 POST가 없으며 실패 시 초안 유지·성공 시 초기화된다. | `NullSuccess`, `P1-GATE` |
|
||||
|
||||
## 9. 반응형 기능 범위
|
||||
|
||||
| 기능 | Desktop | Tablet | Mobile | 비고 |
|
||||
|---|---:|---:|---:|---|
|
||||
| `답글 작성`·`답글 보기` 진입 | 지원 | 지원 | 지원 | 기존 댓글 action layout 재사용 |
|
||||
| 여러 직접 답글 조회·작성 | 지원 | 지원 | 지원 | 기존 page size 20과 pagination 재사용 |
|
||||
|
||||
- 상위 제품의 최소 320px, 200% zoom, keyboard-only와 touch target 기준을 유지한다.
|
||||
- Sheet 내부에서 수평 overflow 없이 form과 action을 사용할 수 있어야 한다.
|
||||
|
||||
## 10. UI/UX Expectations
|
||||
|
||||
### 10.1 디자인과 component 원칙
|
||||
|
||||
- `CommentThread`, `CommentItem`, `CommentForm`을 재사용한다.
|
||||
- 오디오와 커뮤니티에 동일한 action label과 펼침 동작을 사용한다.
|
||||
- 새 component나 dependency를 추가하지 않는다.
|
||||
- 기존 답글이 있는 원댓글의 `답글 보기` UI는 유지한다.
|
||||
|
||||
### 10.2 화면 상태
|
||||
|
||||
- 클릭 직후 기존 답글 loading 상태를 표시한다.
|
||||
- 빈 답글 응답 뒤에도 작성 form을 표시한다.
|
||||
- 조회 오류는 기존 재시도 UI를 사용한다.
|
||||
- 작성 중·성공·실패는 기존 Comments mutation 정책을 사용한다.
|
||||
- 답글 작성 성공 후 form은 빈 값으로 초기화되고 다시 입력할 수 있다.
|
||||
|
||||
### 10.3 접근성
|
||||
|
||||
- 버튼의 accessible name은 원댓글 내용과 `답글 작성` 또는 `답글 보기`를 조합해 식별 가능해야 한다.
|
||||
- form의 visible label과 오류 연결, keyboard focus 표시를 유지한다.
|
||||
- 답글 region은 원댓글 내용과 `답글`을 조합한 accessible name을 유지한다.
|
||||
- keyboard-only로 Sheet의 원댓글에서 답글 form까지 진입하고 등록할 수 있어야 한다.
|
||||
|
||||
## 11. API 계약
|
||||
|
||||
### 11.1 공통 규칙
|
||||
|
||||
- 이 기능은 API를 변경하지 않는다.
|
||||
- 정확한 request, response와 오류는 [기능 API Contract](./api-contract.md)를 따른다.
|
||||
- 원본 OpenAPI는 [프로젝트 OpenAPI](../20260725_AI캐릭터관리자웹/api-contract.openapi.json)다.
|
||||
|
||||
### 11.2 Endpoint 추적
|
||||
|
||||
| 요구사항 | Method | Path | 계약 상태 | 소유 Goal |
|
||||
|---|---|---|---|---|
|
||||
| `CCR-002`, `CCR-004` | GET | `/api/v2/admin/ai-characters/{characterId}/community-posts/{postId}/comments/{commentId}/replies` | 기존 제공·구현됨 | `P1-T1` |
|
||||
| `CCR-003~005` | POST | `/api/v2/admin/ai-characters/{characterId}/community-posts/{postId}/comments` | 기존 제공·구현됨 | `P1-T1` |
|
||||
|
||||
### 11.3 외부 제공 대기 계약
|
||||
|
||||
없음. 필요한 GET·POST, DTO와 mock handler가 이미 제공돼 있다.
|
||||
|
||||
## 12. 보안과 데이터 취급
|
||||
|
||||
- 기존 Bearer 인증, ADMIN 권한과 `characterId`·`postId` target 격리를 유지한다.
|
||||
- `parentId`는 현재 Community target에서 응답받은 활성 원댓글 ID만 사용한다.
|
||||
- 댓글 본문과 인증 정보는 console, 분석 이벤트와 영구 저장소에 기록하지 않는다.
|
||||
- 401·403은 공통 인증·인가 정책을 따른다.
|
||||
- 클라이언트 validation은 서버의 target·parent 소유권 검증을 대체하지 않는다.
|
||||
|
||||
## 13. 성능과 품질 요구사항
|
||||
|
||||
- 답글 action을 누를 때 선택한 원댓글의 답글 page 0만 기존 방식으로 조회한다.
|
||||
- 답글 page size 20과 기존 pagination을 유지하며 전체 답글을 선조회하지 않는다.
|
||||
- 새 dependency, 캐시 계층과 optimistic update를 추가하지 않는다.
|
||||
- Vitest focused test, Comments 회귀, Chromium mock E2E, typecheck와 lint를 통과한다.
|
||||
- server 404나 network error를 mock으로 자동 전환하지 않는다.
|
||||
|
||||
## 14. 성공 기준
|
||||
|
||||
### 14.1 기능 수용 기준
|
||||
|
||||
- [x] 답글 0개인 활성 Community root에서 첫 답글을 작성한다. (`CCR-001~003`)
|
||||
- [x] 같은 원댓글에 여러 직접 답글을 작성·조회한다. (`CCR-004`)
|
||||
- [x] reply row와 비활성 workspace의 2단계·권한 경계가 유지된다. (`CCR-005~006`)
|
||||
- [x] 실패·재시도와 중복 제출 방지가 회귀하지 않는다. (`CCR-006`)
|
||||
|
||||
### 14.2 UI/UX 수용 기준
|
||||
|
||||
- [x] 버튼·답글 region·form의 accessible name과 label이 연결된다.
|
||||
- [x] 320px·200% zoom에서 수평 overflow 없이 답글을 작성한다.
|
||||
- [x] keyboard-only로 답글 form에 진입하고 등록할 수 있다.
|
||||
|
||||
### 14.3 추적성 완료 기준
|
||||
|
||||
- [x] 모든 확정 요구사항이 API 또는 contract 불필요 판정, `P1-T1`, `P1-GATE`와 연결된다.
|
||||
- [x] 구현·검증 결과가 [plan-task.md](./plan-task.md)의 Progress에 기록된다.
|
||||
- [x] 완료된 Phase의 리뷰가 `reviews/` 아래에 기록된다.
|
||||
|
||||
## 15. Open Questions
|
||||
|
||||
없음.
|
||||
|
||||
## 16. 요구사항 추적표
|
||||
|
||||
| 요구사항 범위 | API Contract | 계획 Phase | Goal | 자동 검증 | 수동 검증 |
|
||||
|---|---|---:|---|---|---|
|
||||
| `CCR-001~006` | [api-contract.md](./api-contract.md) | 1 | `P1-T1`, `P1-GATE` | `comment-thread.test.tsx`, `comments.spec.ts` | 활성 Community 첫·추가 답글, 비활성·2단계·320px·keyboard 경계 |
|
||||
|
||||
## 17. Decision Log
|
||||
|
||||
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항·계약·Goal |
|
||||
|---|---|---|---|---|---|
|
||||
| 2026-08-06 | `CCR-DEC-001` | 확정 | 오디오 콘텐츠와 동일한 첫 답글 진입을 활성 커뮤니티 원댓글에도 적용한다. | 사용자 요청 | `CCR-001~003`, `P1-T1` |
|
||||
| 2026-08-06 | `CCR-DEC-002` | 확정 | 댓글 트리는 원댓글 아래 여러 직접 답글을 허용하되 답글의 답글은 허용하지 않는다. | 사용자 요청의 “1단계 추가, 여러 개” 조건 | `CCR-004~005`, [api-contract.md](./api-contract.md) |
|
||||
| 2026-08-06 | `CCR-DEC-003` | 확정 | 새 API·컴포넌트 없이 기존 Community GET·POST와 Comments UI를 재사용한다. | OpenAPI와 구현 확인 | `CCR-002~006`, `P1-T1` |
|
||||
|
||||
## 18. 변경 관리
|
||||
|
||||
- 범위가 바뀌면 이 문서의 Decision Log와 요구사항을 먼저 갱신한다.
|
||||
- API가 바뀌면 [api-contract.md](./api-contract.md)와 원본 OpenAPI의 제공 버전을 확인한다.
|
||||
- 구현 범위가 바뀌면 코드보다 [plan-task.md](./plan-task.md)를 먼저 갱신한다.
|
||||
- 기존 Progress, review와 검증 기록은 삭제하거나 덮어쓰지 않는다.
|
||||
Reference in New Issue
Block a user