11 KiB
11 KiB
라이브 크리에이터 입장 제한 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. 핵심 사용자 흐름
- 일반 유저 또는 방 생성자가
isAvailableJoinCreator = false방을 조회하면 기존 정책에 따라 표시된다. - 성별 제한에 맞지 않는 사용자가
genderRestriction제한 방을 v2 홈 추천/온에어 라이브에서 조회하면 표시되지 않는다. - 다른 크리에이터가 같은 방을 v2 홈 추천/온에어 라이브 또는 크리에이터 채널 라이브 경로에서 조회하면 표시되지 않는다.
- 성별 제한에 맞지 않는 사용자가 방 ID를 알고
/live/room/enter를 호출하면 입장이 거부된다. - 다른 크리에이터가 방 ID를 알고
/live/room/enter를 호출하면 입장이 거부된다. - 방 생성 크리에이터가 본인 방에 입장하면 기존처럼 허용된다.
/enter에서 거절되는 다른 크리에이터 또는 성별 불일치 사용자가/live/room/info/{id}를 호출하면 토큰 생성 전에 같은 정책으로 거절된다.- 방 생성자, 성별이 맞는 일반 사용자, 크리에이터 입장이 허용된 방의 다른 크리에이터는 기존처럼 방 정보와 토큰을 받는다.
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. 성공 기준
- 다른 크리에이터는
isAvailableJoinCreator = false방을 v2 홈 추천/온에어 라이브에서 받지 않는다. (LCR-001) - 성별 제한에 맞지 않는 사용자는
genderRestriction제한 방을 v2 홈 추천/온에어 라이브에서 받지 않는다. (LCR-001) - 다른 크리에이터는
isAvailableJoinCreator = false방을 v2 크리에이터 채널 라이브 탭에서 받지 않는다. (LCR-002) - 다른 크리에이터는
isAvailableJoinCreator = false방에 직접 입장할 수 없다. (LCR-003) - 성별 제한에 맞지 않는 사용자는 제한 방에 직접 입장할 수 없다. (
LCR-003) - 방 생성 크리에이터 본인은 본인 방을 조회하고 입장할 수 있다. (
LCR-001~LCR-003) - 공개 API 스키마 변경 없이 focused test와 영향 범위 회귀가 통과한다.
- 다른 크리에이터와 성별 불일치 사용자는
/live/room/info/{id}에서 토큰 생성 전에 거절되고 토큰 생성기가 호출되지 않는다. (LCR-003) - 방 생성자, 성별이 맞는 일반 사용자, 크리에이터 입장이 허용된 방의 다른 크리에이터,
Gender.NONE사용자는 기존처럼 방 정보와 토큰을 받는다. (LCR-003,LCR-004) - 채널 소유자 본인은
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 범위를 먼저 갱신한다.