docs(live-room): 입장 제한 요구사항과 계획을 기록한다
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
# 라이브 크리에이터 입장 제한 PRD
|
||||
|
||||
## 문서 정보
|
||||
|
||||
| 항목 | 내용 |
|
||||
|---|---|
|
||||
| 문서 상태 | Phase 1~3 구현 및 검증 완료 |
|
||||
| 작성일 | `2026-09-17` |
|
||||
| 최종 수정일 | `2026-09-17` |
|
||||
| 대상 제품 | 라이브 방 목록 노출 및 입장 제한 |
|
||||
| 작성자·결정권자 | Sisyphus / 사용자 |
|
||||
| 관련 API Contract | 기존 API 응답 스키마 변경 없음 |
|
||||
| 관련 구현 계획 | `docs/20260917_라이브_크리에이터_입장제한/plan-task.md` |
|
||||
| 관련 review | `reviews/현재변경사항-review.md` (`REV-001`, `REV-002`) |
|
||||
|
||||
## 1. Overview
|
||||
|
||||
라이브 방 생성자가 `isAvailableJoinCreator = false`로 설정한 방은 다른 크리에이터 계정에게 노출되거나 입장 가능하면 안 된다. 또한 `genderRestriction`으로 입장 가능 성별이 제한된 방은 조회 단계에서도 입장 가능한 사용자에게만 노출돼야 한다. 기존 `/live/room` 계열 조회는 대부분 이 정책을 적용하지만, v2 홈 추천/온에어 라이브와 일부 크리에이터 채널 라이브 경로에서 정책 누락 가능성이 확인됐다. 후속 리뷰에서 `/live/room/info/{id}`가 같은 제한을 확인하지 않고 RTC/RTM 토큰을 발급하는 경로도 확인됐다.
|
||||
|
||||
## 2. Problem Statement
|
||||
|
||||
- `v2` 홈 추천/온에어 라이브 조회는 `findLiveRecommendations()`에서 조회자의 크리에이터 여부와 유효 성별을 받지 않아 `isAvailableJoinCreator = false`인 방도 크리에이터에게 노출될 수 있고, 성별 제한 방도 입장 불가능한 사용자에게 노출될 수 있다.
|
||||
- `v2` 크리에이터 채널 라이브 탭은 조회자가 크리에이터인지가 아니라 조회자가 해당 채널 주인인지로만 `isViewerCreator`를 계산해, 다른 크리에이터에게 제한 방이 노출될 수 있다.
|
||||
- `/live/room/enter`는 성인, 비공개, 차단, 강퇴, 성별, 정원, 결제 조건은 확인하지만 크리에이터 입장 제한을 최종 차단하지 않는다.
|
||||
- `/live/room/info/{id}`는 방 정보와 상호 차단만 확인한 뒤 RTC/RTM 토큰을 생성하므로 `/enter`에서 거절된 사용자도 토큰 발급을 요청할 수 있다.
|
||||
|
||||
문제를 해결했다는 판단은 다른 크리에이터가 `isAvailableJoinCreator = false` 방을 리스트에서 보지 못하고, 성별 제한에 맞지 않는 사용자가 제한 방을 리스트에서 보지 못하며, 직접 `enter` 요청을 보내도 차단되는 것으로 한다.
|
||||
|
||||
## 3. Goals
|
||||
|
||||
- 다른 크리에이터 계정은 `isAvailableJoinCreator = false` 라이브 방을 문제 의심 경로에서 볼 수 없다.
|
||||
- 다른 크리에이터 계정은 `isAvailableJoinCreator = false` 라이브 방에 직접 입장할 수 없다.
|
||||
- 입장 가능 성별이 제한된 라이브 방은 성별이 맞는 사용자 또는 방 생성자 본인에게만 조회된다.
|
||||
- 입장 가능 성별이 제한된 라이브 방은 성별이 맞는 사용자 또는 방 생성자 본인만 입장할 수 있다.
|
||||
- 방을 만든 크리에이터 본인은 예외로 계속 조회 및 입장 가능하다.
|
||||
- 제한 사용자는 `/live/room/info/{id}`에서 RTC/RTM/v2v 토큰을 발급받을 수 없다.
|
||||
- 기존 응답 DTO와 공개 API 스키마는 변경하지 않는다.
|
||||
|
||||
## 4. Non-Goals
|
||||
|
||||
- `isAvailableJoinCreator` 필드명, 의미, DB 스키마 변경은 하지 않는다.
|
||||
- 일반 유저, 관리자, 봇, 에이전트의 기존 노출/입장 정책은 변경하지 않는다.
|
||||
- 기존 성인/성별/차단/강퇴/비공개/결제 정책은 재설계하지 않는다.
|
||||
- `Gender.NONE` 사용자의 기존 정책은 변경하지 않는다. 기존 `Member.canEnter()`와 리스트 조건처럼 성별 미설정 사용자는 성별 제한을 통과한다.
|
||||
- 새 API endpoint나 새 응답 필드는 만들지 않는다.
|
||||
|
||||
## 5. Target Users and Permissions
|
||||
|
||||
| 사용자 | 목표 | 정책 |
|
||||
|---|---|---|
|
||||
| 방 생성 크리에이터 | 본인이 만든 방 조회 및 입장 | `isAvailableJoinCreator = false`여도 허용 |
|
||||
| 다른 크리에이터 | 크리에이터 입장 제한 방 접근 방지 | `isAvailableJoinCreator = false`면 목록 미노출 및 입장 차단 |
|
||||
| 일반 유저 | 기존 라이브 조회 및 입장 | `genderRestriction`에 맞으면 허용, `Gender.NONE`은 기존처럼 허용 |
|
||||
|
||||
## 6. 핵심 사용자 흐름
|
||||
|
||||
1. 일반 유저 또는 방 생성자가 `isAvailableJoinCreator = false` 방을 조회하면 기존 정책에 따라 표시된다.
|
||||
2. 성별 제한에 맞지 않는 사용자가 `genderRestriction` 제한 방을 v2 홈 추천/온에어 라이브에서 조회하면 표시되지 않는다.
|
||||
3. 다른 크리에이터가 같은 방을 v2 홈 추천/온에어 라이브 또는 크리에이터 채널 라이브 경로에서 조회하면 표시되지 않는다.
|
||||
4. 성별 제한에 맞지 않는 사용자가 방 ID를 알고 `/live/room/enter`를 호출하면 입장이 거부된다.
|
||||
5. 다른 크리에이터가 방 ID를 알고 `/live/room/enter`를 호출하면 입장이 거부된다.
|
||||
6. 방 생성 크리에이터가 본인 방에 입장하면 기존처럼 허용된다.
|
||||
7. `/enter`에서 거절되는 다른 크리에이터 또는 성별 불일치 사용자가 `/live/room/info/{id}`를 호출하면 토큰 생성 전에 같은 정책으로 거절된다.
|
||||
8. 방 생성자, 성별이 맞는 일반 사용자, 크리에이터 입장이 허용된 방의 다른 크리에이터는 기존처럼 방 정보와 토큰을 받는다.
|
||||
|
||||
## 7. 기능 요구사항
|
||||
|
||||
| ID | 상태 | 요구사항 | 수용 기준 | 계약/Goal 연결 |
|
||||
|---|---|---|---|---|
|
||||
| `LCR-001` | 확정 | v2 홈 추천/온에어 라이브 조회에서 다른 크리에이터에게 `isAvailableJoinCreator = false` 방을 숨기고, 성별 제한에 맞지 않는 사용자에게 `genderRestriction` 제한 방을 숨긴다. | `HomeRecommendationQueryService.findLiveRecommendations()` 호출 경로가 조회자 크리에이터 여부와 유효 성별을 전달한다. repository는 `liveRoom.isAvailableJoinCreator.isTrue.or(liveRoom.member.id.eq(memberId))`와 `Gender.MALE -> ALL/MALE_ONLY`, `Gender.FEMALE -> ALL/FEMALE_ONLY`, `Gender.NONE/null -> 필터 없음` 조건을 적용한다. | `P1-T1` |
|
||||
| `LCR-002` | 확정 | v2 크리에이터 채널 라이브 탭에서 다른 크리에이터에게 제한 방을 숨긴다. | `CreatorChannelLiveQueryService`가 `viewer.role == MemberRole.CREATOR` 기준으로 조회자 크리에이터 여부를 전달한다. 방 생성자 본인은 예외다. | `P1-T2` |
|
||||
| `LCR-003` | 확정 | `/live/room/enter`와 `/live/room/info/{id}`에서 다른 크리에이터의 제한 방 입장·토큰 발급과 성별 제한에 맞지 않는 접근을 차단한다. | 다른 크리에이터 제한은 `live.room.not_found`, 성별 제한은 `live.room.gender_restricted`로 결제·입장 상태 변경 또는 RTC/RTM/v2v 토큰 생성 전에 거절한다. 생성자는 예외이며 성별 판정은 `Member.canEnter()`를 재사용한다. | `P2-T1`, `P3-T1` |
|
||||
| `LCR-004` | 확정 | 기존 정상 경로는 유지한다. | 일반 유저와 방 생성자 본인의 조회/입장 동작은 유지되고 기존 테스트 또는 신규 회귀 테스트로 확인된다. | `P2-GATE` |
|
||||
|
||||
## 8. API 계약
|
||||
|
||||
- 변경되는 공개 request/response 필드는 없다.
|
||||
- `/live/room/enter`는 기존 오류 envelope를 사용한다.
|
||||
- `/live/room/info/{id}`도 기존 오류 envelope와 message key를 재사용하며 응답 필드는 변경하지 않는다.
|
||||
- 신규 message key 추가 여부는 구현 단계에서 기존 `live.room.gender_restricted`, `common.error.invalid_request`, `live.room.not_found` 패턴을 확인해 결정한다. 새 key가 필요하면 메시지 리소스와 테스트를 함께 갱신한다.
|
||||
|
||||
## 9. 보안과 데이터 취급
|
||||
|
||||
- 숨김 정책은 클라이언트 표시만으로 끝내지 않고 서버 입장 경계에서 한 번 더 차단한다.
|
||||
- 제한 방 존재 여부를 다른 크리에이터에게 과도하게 노출하지 않는 오류 메시지를 우선한다.
|
||||
- 민감정보, 결제 정보, password, token은 로그나 테스트 fixture에 기록하지 않는다.
|
||||
- 제한 검사는 RTC, RTM, v2v 토큰 생성 호출보다 먼저 수행한다.
|
||||
|
||||
## 10. 성공 기준
|
||||
|
||||
- [x] 다른 크리에이터는 `isAvailableJoinCreator = false` 방을 v2 홈 추천/온에어 라이브에서 받지 않는다. (`LCR-001`)
|
||||
- [x] 성별 제한에 맞지 않는 사용자는 `genderRestriction` 제한 방을 v2 홈 추천/온에어 라이브에서 받지 않는다. (`LCR-001`)
|
||||
- [x] 다른 크리에이터는 `isAvailableJoinCreator = false` 방을 v2 크리에이터 채널 라이브 탭에서 받지 않는다. (`LCR-002`)
|
||||
- [x] 다른 크리에이터는 `isAvailableJoinCreator = false` 방에 직접 입장할 수 없다. (`LCR-003`)
|
||||
- [x] 성별 제한에 맞지 않는 사용자는 제한 방에 직접 입장할 수 없다. (`LCR-003`)
|
||||
- [x] 방 생성 크리에이터 본인은 본인 방을 조회하고 입장할 수 있다. (`LCR-001`~`LCR-003`)
|
||||
- [x] 공개 API 스키마 변경 없이 focused test와 영향 범위 회귀가 통과한다.
|
||||
- [x] 다른 크리에이터와 성별 불일치 사용자는 `/live/room/info/{id}`에서 토큰 생성 전에 거절되고 토큰 생성기가 호출되지 않는다. (`LCR-003`)
|
||||
- [x] 방 생성자, 성별이 맞는 일반 사용자, 크리에이터 입장이 허용된 방의 다른 크리에이터, `Gender.NONE` 사용자는 기존처럼 방 정보와 토큰을 받는다. (`LCR-003`, `LCR-004`)
|
||||
- [x] 채널 소유자 본인은 `isAvailableJoinCreator = false`인 현재 방을 repository 조회에서 받는다. (`LCR-002`, `LCR-004`)
|
||||
|
||||
## 11. Decision Log
|
||||
|
||||
| 일시 | 결정 | 근거 |
|
||||
|---|---|---|
|
||||
| 2026-09-17 | `isAvailableJoinCreator = false`는 다른 크리에이터만 제한하고 방 생성자 본인은 예외로 둔다. | 기존 QueryDSL 조건들이 `liveRoom.member.id.eq(viewerId)` 예외를 두는 패턴과 사용자 선택 A |
|
||||
| 2026-09-17 | 이 작업은 문서가 필요한 구현 작업으로 분류한다. | 저장소 `AGENTS.md`와 `docs/agent-guides/작업절차.md`가 모든 구현 작업 전 PRD와 plan-task를 요구 |
|
||||
| 2026-09-17 | v2 홈 추천/온에어 라이브에도 기존 조회 경로와 같은 `genderRestriction` 필터를 적용한다. | `/live/room`, 팔로잉, 크리에이터 채널 조회 경로가 이미 성별 조건을 조회 단계에서 적용하고 있으며 사용자가 문서 반영을 요청 |
|
||||
| 2026-09-17 | `/live/room/enter`의 성별 제한은 기존 `Member.canEnter()` 정책을 유지한다. | 현재 `LiveRoomService.enterLive()`가 이미 `room.member.id != member.id && !member.canEnter(room.genderRestriction)`을 차단하고, `Gender.NONE`은 `canEnter()`에서 허용됨 |
|
||||
| 2026-09-17 | `/live/room/info/{id}`에서도 `/enter`와 같은 크리에이터·성별 제한을 토큰 생성 전에 적용한다. | `REV-001`에서 `/enter` 거절 후에도 RTC/RTM/v2v 토큰 생성 경로가 열려 있음을 코드로 확인 |
|
||||
| 2026-09-17 | 채널 소유자의 제한 방 조회는 production 변경 없이 H2 repository 회귀 테스트로 고정한다. | `REV-002`와 기존 `creatorJoinLiveCondition()`의 소유자 예외 |
|
||||
|
||||
## 12. 열린 질문
|
||||
|
||||
- 없음. 구현 중 기존 메시지 key 재사용이 부적절하다고 확인되면 plan-task 범위를 먼저 갱신한다.
|
||||
Reference in New Issue
Block a user