Files
voiceon-character-admin/docs/20260806_댓글액션버튼라벨/prd.md

216 lines
11 KiB
Markdown

# 댓글 액션 버튼 표시 라벨 간소화 PRD
## 문서 정보
| 항목 | 내용 |
|---|---|
| 문서 상태 | 구현 완료 |
| 작성일 | 2026-08-06 |
| 최종 수정일 | 2026-08-06 |
| 대상 제품 | AI 캐릭터 관리자 웹의 Audio·Community 댓글 관리 |
| 작성자·결정권자 | Codex 작성, 사용자 결정 |
| 관련 API Contract | 불필요 — 기존 댓글 API와 payload를 변경하지 않음 |
| 관련 구현 계획 | [plan-task.md](./plan-task.md) |
| 관련 review | 없음 |
### 요구사항 상태
| 상태 | 의미 | 구현 처리 |
|---|---|---|
| 확정 | 제품·기술 결정이 완료된 구현 기준 | `plan-task.md`의 Task와 완료 증거로 추적 |
| 미결 | 추가 결정 필요 | 구현 전 결정 |
| 외부 의존 | 프론트엔드 밖의 제공 필요 | 제공 전 관련 구현 중단 |
| 권고 | 확정 전 추천안 | 수용 기준으로 사용하지 않음 |
| 제외 | 이번 범위에서 구현하지 않음 | 포함 조건을 Decision Log에 기록 |
### 문서 우선순위와 갱신 순서
1. 표시 라벨과 accessible name 결정은 이 PRD가 소유한다.
2. API 변경은 없으므로 별도 API Contract를 만들지 않는다.
3. 구현 범위·순서·완료 증거는 `plan-task.md`가 소유한다.
4. 결정이 바뀌면 Decision Log → 요구사항 → 계획 순서로 갱신한다.
## 1. Overview
댓글 본문과 각 액션 버튼에 반복되는 댓글 내용을 분리한다. 화면에는 `답글 작성`, `답글 보기`, `수정`, `삭제`만 표시하고, 스크린 리더용 accessible name에는 기존처럼 `댓글 내용 + 동작`을 유지한다.
## 2. Problem Statement
현재 `CommentItem`은 댓글 본문을 별도로 표시하면서 버튼에도 같은 내용을 반복한다.
- 긴 댓글일수록 액션 영역이 커지고 동작명을 빠르게 구분하기 어렵다.
- 한 댓글의 여러 버튼에 같은 문장이 반복되어 모바일에서 시각적 밀도가 높아진다.
- 화면 표시 문구와 accessible name이 결합돼 있어 시각적 간소화와 보조기술 문맥 제공을 독립적으로 조정할 수 없다.
문제를 해결했다는 판단은 버튼 화면 텍스트가 동작명만 포함하고, 같은 버튼의 accessible name은 대상 댓글과 동작을 함께 식별할 때로 한다.
## 3. Goals
### 3.1 제품 목표
- 사용자가 댓글 본문과 액션을 빠르게 구분한다.
- Audio·Community의 공유 댓글 UI에 같은 규칙을 적용한다.
- 기존 조회·작성·수정·삭제 동작과 권한을 유지한다.
### 3.2 UX 목표
- 버튼 화면 텍스트를 `답글 작성`, `답글 보기`, `수정`, `삭제`로 제한한다.
- 스크린 리더가 버튼만 탐색해도 대상 댓글과 동작을 구분하게 한다.
- 320px 화면에서 긴 댓글이 액션 버튼마다 반복되지 않게 한다.
## 4. Non-Goals
- 댓글 API, DTO, pagination, mutation 또는 권한 정책 변경
- 댓글 본문, 작성 form, 답글 region의 label 변경
- FanTalk 답변 버튼과 Community 게시글 열기 버튼 변경
- 액션 버튼의 배치, 색상, 크기, 확인 dialog 또는 삭제 복원 기능 변경
Non-Goal을 변경하려면 Decision Log와 `plan-task.md`를 먼저 갱신한다.
## 5. Target Users and Permissions
| 사용자 | 목표 | 주요 작업 | 사용 환경 |
|---|---|---|---|
| ADMIN | 댓글별 액션을 빠르게 구분 | 답글 열기·작성, AI 댓글 수정, 댓글 삭제 | desktop, tablet, mobile |
| 읽기 전용 ADMIN | 댓글과 기존 답글 조회 | 답글 보기 | desktop, tablet, mobile |
- 기존 `canMutate`, 작성자 판정과 비활성 workspace 정책을 그대로 사용한다.
- 라벨 변경으로 숨겨진 액션이 새로 노출되거나 기존 액션이 제거되지 않는다.
## 6. 핵심 사용자 흐름
1. 사용자가 Audio 상세 또는 Community 게시글 Sheet의 댓글 목록을 연다.
2. 댓글 본문은 카드 본문에서 한 번 읽고, 액션 영역에서는 짧은 동작명을 확인한다.
3. 사용자가 `답글 작성`·`답글 보기`·`수정`·`삭제` 중 허용된 버튼을 실행한다.
4. 스크린 리더는 각 버튼을 `댓글 내용 + 동작`으로 안내한다.
5. 기존 form, network request와 성공·실패 처리가 그대로 동작한다.
## 7. 정보 구조와 라우팅
```text
/ai-characters/:characterId/audio-contents/:contentId
/ai-characters/:characterId/community-posts
└─ 게시글 Sheet의 댓글 관리
```
- 새 route와 URL 상태를 추가하지 않는다.
- 두 진입점은 공유 `CommentThread``CommentItem`을 사용한다.
## 8. 기능 요구사항
### 8.1 표시 라벨과 accessible name
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|---|---|---|---|---|
| `CLB-001` | 확정 | 답글 액션의 화면 텍스트에는 `답글 작성` 또는 `답글 보기`만 표시한다. | 원댓글의 답글 버튼 `textContent`가 전달된 `replyActionLabel`과 정확히 일치한다. | contract 불필요, `P1-T1` |
| `CLB-002` | 확정 | 수정 액션의 화면 텍스트에는 `수정`만 표시한다. | 수정 가능한 원댓글·답글 버튼의 `textContent``수정`과 정확히 일치한다. | contract 불필요, `P1-T1` |
| `CLB-003` | 확정 | 삭제 액션의 화면 텍스트에는 `삭제`만 표시한다. | 삭제 가능한 원댓글·답글 버튼의 `textContent``삭제`와 정확히 일치한다. | contract 불필요, `P1-T1` |
| `CLB-004` | 확정 | 각 액션 버튼의 accessible name에는 댓글 내용과 화면 동작명을 함께 유지한다. | role·name 조회에서 `댓글 내용 + 답글 작성/답글 보기/수정/삭제`로 각 버튼을 찾을 수 있고, visible label도 accessible name에 포함된다. | contract 불필요, `P1-T1` |
| `CLB-005` | 확정 | 공유 `CommentItem`을 사용하는 Audio·Community 원댓글과 답글에 동일한 규칙을 적용한다. | 두 target의 기존 단위·E2E 흐름이 통과하며 reply row에는 기존처럼 답글 액션이 없다. | contract 불필요, `P1-GATE` |
| `CLB-006` | 확정 | 라벨 외 동작·권한·상태는 변경하지 않는다. | 기존 GET·POST·PUT·DELETE 경로와 payload, disabled 조건, form 초기화·오류 복구 test가 통과한다. | 기존 댓글 계약 재사용, `P1-GATE` |
### 8.2 공통 파일·데이터 정책
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|---|---|---|---|---|
| `CLB-007` | 확정 | 댓글 원문은 가공·축약하지 않고 현재 값으로 accessible name을 구성한다. | 별도 상태·helper·dependency 없이 `CommentItem``comment.comment`와 동작명을 사용한다. | contract 불필요, `P1-T1` |
## 9. 반응형 기능 범위
| 기능 | Desktop | Tablet | Mobile | 비고 |
|---|---:|---:|---:|---|
| 짧은 화면 표시 라벨 | 지원 | 지원 | 지원 | 공유 component 적용 |
| 문맥을 포함한 accessible name | 지원 | 지원 | 지원 | viewport와 무관 |
| 기존 댓글 액션 | 유지 | 유지 | 유지 | 권한·상태 변경 없음 |
- 최소 320px에서 수평 overflow 없이 액션을 사용할 수 있어야 한다.
- 200% zoom에서도 댓글 본문과 액션을 구분할 수 있어야 한다.
## 10. UI/UX Expectations
### 10.1 디자인과 component 원칙
- 댓글 본문은 카드 본문이, 동작명은 버튼이 각각 한 번만 시각적으로 표시한다.
- 기존 버튼 style, semantic color와 최소 높이 규칙을 유지한다.
- 새 component나 공통 helper를 만들지 않고 공유 `CommentItem`에서 처리한다.
### 10.2 화면 상태
- pending 중 disabled 처리와 loading status를 유지한다.
- 수정 mode의 `수정 저장`, `취소` 문구는 대상이 아니므로 유지한다.
- 오류·성공·empty 상태를 변경하지 않는다.
### 10.3 접근성
- visible label과 accessible name을 분리하되 visible label 전체가 accessible name에 포함돼야 한다.
- 동일 동작 버튼을 보조기술로 단독 탐색해도 댓글 내용으로 대상을 구분할 수 있어야 한다.
- button semantic, keyboard focus 순서와 focus 표시를 유지한다.
- axe critical·serious 위반 0건을 유지한다.
## 11. API 계약
### 11.1 공통 규칙
- 이번 변경은 표시 계층에만 적용한다.
- 기존 Audio·Community 댓글 endpoint, request/response, 오류와 pagination 계약을 변경하지 않는다.
### 11.2 Endpoint 추적
| 요구사항 | Method | Path | 계약 상태 | API Contract | 소유 Goal |
|---|---|---|---|---|---|
| `CLB-001~007` | 해당 없음 | 해당 없음 | 변경 불필요 | 기존 댓글 계약 유지 | `P1-T1`, `P1-GATE` |
### 11.3 외부 제공 대기 계약
없음.
## 12. 보안과 데이터 취급
- 댓글 내용은 현재처럼 DOM과 접근성 트리에 표시되며 새 저장·전송·log를 추가하지 않는다.
- 인증, 리소스 ownership과 mutation 권한 정책을 변경하지 않는다.
- 라벨을 analytics 또는 외부 서비스로 전송하지 않는다.
## 13. 성능과 품질 요구사항
- 새 dependency, state, effect 또는 network request를 추가하지 않는다.
- React 19.2.8, TypeScript 6.0.3과 기존 지원 browser를 유지한다.
- focused unit test, Comments mock E2E, typecheck, lint와 production build를 Gate로 사용한다.
- backend와 mock 계약 변경이 없으므로 별도 preview mode를 추가하지 않는다.
## 14. 성공 기준
### 14.1 기능 수용 기준
- [x] Audio·Community 댓글의 화면 액션은 짧은 동작명만 표시한다. (`CLB-001~003`)
- [x] 기존 답글·수정·삭제 동작과 권한이 유지된다. (`CLB-005~006`)
### 14.2 UI/UX 수용 기준
- [x] 모든 대상 버튼의 visible label과 contextual accessible name이 분리된다. (`CLB-004`)
- [x] 320px와 200% zoom에서 액션 사용과 본문 구분에 문제가 없다.
- [x] keyboard 흐름과 axe critical·serious 0건을 유지한다.
### 14.3 추적성 완료 기준
- [x] `CLB-001~007``P1-T1` 또는 `P1-GATE` 완료 증거로 연결된다.
- [x] API Contract가 불필요한 표시 계층 변경임을 기록했다.
- [x] 미결·외부 의존 항목이 없다.
## 15. Open Questions
없음. 사용자는 화면 표시에서만 댓글 내용을 제거하고 accessible name에는 댓글 문맥을 유지하는 A안을 선택했다.
## 16. 요구사항 추적표
| 요구사항 범위 | API Contract | 계획 Phase | Goal | 자동 검증 | 수동 검증 |
|---|---|---:|---|---|---|
| `CLB-001~004`, `CLB-007` | 불필요 | 1 | `P1-T1` | `comment-thread.test.tsx` | 화면 텍스트와 접근성 트리 비교 |
| `CLB-005~006` | 기존 계약 유지 | 1 | `P1-GATE` | Comments unit·E2E, typecheck, lint, build | 1280px·320px·200% zoom·keyboard |
## 17. Decision Log
| 날짜 | ID | 상태 | 결정 | 근거 | 영향 요구사항·계약·Goal |
|---|---|---|---|---|---|
| 2026-08-06 | `CLB-DEC-001` | 확정 | 화면 버튼에서는 댓글 내용을 제거하고 accessible name에는 `댓글 내용 + 동작`을 유지한다. | 사용자 선택 A. 시각적 중복을 줄이면서 보조기술의 대상 식별을 보존한다. | `CLB-001~004`, `P1-T1` |
| 2026-08-06 | `CLB-DEC-002` | 확정 | 공유 `CommentItem` 한 곳에서 Audio·Community 원댓글과 답글의 표시를 변경한다. | 모든 대상 호출이 같은 component를 사용하며 API·상태 변경이 필요 없다. | `CLB-005~007`, `P1-T1`, `P1-GATE` |