2026. 7. 10. 01:17ㆍ프로젝트/HOTSPOT
1. 왜 크리에이터 역할을 따로 분리해야 했나?
이번 작업의 출발점은 단순히 CREATOR라는 권한을 하나 더 추가하는 것이 아니었다. HOTSPOT에서는 매니저가 상품과 방송을 운영하는 흐름이 이미 있었고, 여기에 크리에이터가 판매와 홍보의 주체로 참여하는 구조가 추가되고 있었다.
문제는 크리에이터를 매니저의 하위 개념처럼만 다루면 데이터가 금방 애매해진다는 점이다. 예를 들어 판매가 발생했을 때 이 실적을 매니저에게 귀속해야 하는지, 크리에이터에게 귀속해야 하는지 명확하지 않으면 랭킹, 캠페인 성과, 정산 기준이 모두 흔들린다.
그래서 이번 작업에서는 크리에이터를 별도의 활동 주체로 보고, 검색 결과, 프로필, 라이브 상태, OBS 위젯, 랭킹 적립 흐름까지 같은 기준으로 연결하는 쪽에 초점을 맞췄다.
2. 역할 분리에서 중요한 기준
2-1) 권한과 데이터 소유자는 다르다
권한은 사용자가 어떤 기능에 접근할 수 있는지를 결정한다. 반면 데이터 소유자는 어떤 행위의 결과가 누구에게 귀속되는지를 결정한다. 둘은 비슷해 보이지만 실제 구현에서는 분리해서 생각해야 한다.
enum Role {
USER,
MANAGER,
CREATOR,
ADMIN
}
위와 같은 역할 값은 접근 제어에는 유용하다. 하지만 판매 실적을 저장할 때는 단순히 role == CREATOR인지 확인하는 것만으로 부족하다. 실제 판매를 주도한 크리에이터 ID가 존재하는지, 매니저와 어떤 관계인지, 캠페인에 연결되어 있는지도 함께 확인해야 한다.
2-2) 검색 결과도 역할 기준을 따라야 한다
프론트엔드에서는 검색 결과에 매니저뿐 아니라 크리에이터도 포함되도록 수정했다. 이 작업이 필요한 이유는 사용자가 서비스를 탐색할 때 역할의 차이를 몰라도 원하는 대상을 찾을 수 있어야 하기 때문이다.
즉 검색 API와 화면은 내부 권한 구조를 그대로 노출하는 것이 아니라, 사용자가 찾는 대상이 누구인지에 맞춰 결과를 통합해서 보여줘야 한다.
3. 랭킹 귀속은 어떻게 처리해야 하나?
랭킹 적립에서 핵심은 판매를 만든 주체를 명확히 저장하는 것이다. 기존처럼 매니저 ID만 기준으로 저장하면 크리에이터가 실제로 판매를 유도했더라도 데이터상으로는 매니저 성과처럼 보일 수 있다.
Long rankingOwnerId;
if (creatorId != null) {
rankingOwnerId = creatorId;
} else {
rankingOwnerId = managerId;
}
실제 구현에서는 위 예시보다 더 많은 검증이 필요하다. creatorId가 있다고 해서 무조건 신뢰하면 안 되고, 해당 크리에이터가 현재 판매 흐름과 연결되어 있는지 확인해야 한다. 이번 작업에서 파트너십 검증을 추가한 것도 이 때문이다.
※ 여기서 주의할 점
- 랭킹은 화면 표시용 데이터처럼 보이지만 실제로는 보상과 정산의 근거가 될 수 있다.
- 귀속 기준을 나중에 바꾸면 이미 쌓인 데이터를 재처리해야 한다.
- 따라서 판매 발생 시점에 가능한 한 명확한 기준으로 owner를 저장해야 한다.
4. 라이브 상태와 OBS 위젯을 같이 본 이유
크리에이터 기능에서 라이브 상태는 단순한 프로필 속성이 아니다. 프론트엔드 화면, 사이드바 표시, OBS 위젯, SSE 연결 상태와 연결된다. 그래서 백엔드에서 라이브 상태를 변경하는 API를 추가하는 것만으로는 충분하지 않았다.
OBS 위젯은 방송 화면에 바로 노출되는 영역이다. 사용자가 서비스 화면에서는 라이브 상태라고 보는데 OBS 위젯에서는 꺼져 있거나, 반대로 위젯 미리보기를 닫았는데 상태가 잘못 초기화되면 실제 방송 운영에서 혼란이 생긴다.
// 개념적으로는 상태의 출처를 하나로 맞춰야 한다.
member.isLive = obsConnection.isConnected() || explicitLiveStatus;
이번 작업에서는 isLive 값이 응답에 포함되도록 보완하고, OBS SSE 연결 상태와 라이브 상태가 어긋나지 않도록 흐름을 정리했다.
5. OAuth와 탈퇴 처리에서 나온 방어 코드
기능 확장 중 같이 정리한 부분은 계정 처리다. 카카오나 구글 OAuth에서는 이메일이 항상 내려온다고 가정하면 안 된다. 이메일이 null인 상태에서 사용자를 생성하거나 조회하면 NPE가 발생할 수 있고, 임시 이메일을 잘못 노출하면 사용자 경험도 나빠진다.
if (oauthEmail == null) {
return redirectToEmailInputPage();
}
탈퇴 처리도 마찬가지다. 탈퇴 계정의 이메일과 아이디를 중복 체크 대상에서 제외하고, OAuth 연동 정보와 개인정보를 함께 정리해야 재가입이나 관리자 강제 탈퇴 상황에서 데이터가 꼬이지 않는다.
6. 코드 관점에서 다시 확인할 부분
이번 작업에서 다시 확인해야 할 지점은 역할 값 자체보다 역할이 사용되는 위치다. 컨트롤러에서는 인증된 사용자가 어떤 기능에 접근할 수 있는지 확인하고, 서비스 계층에서는 실제 데이터가 어느 사용자에게 귀속되어야 하는지 검증해야 한다.
private Long resolveRankingOwner(Long managerId, Long creatorId) {
if (creatorId == null) {
return managerId;
}
validateCreatorPartnership(managerId, creatorId);
return creatorId;
}
이렇게 분리하면 권한 체크와 귀속 기준이 한 메서드 안에서 뒤섞이지 않는다. 나중에 정산, 통계, 랭킹 조건이 추가되더라도 어느 지점에서 검증을 강화해야 하는지 찾기 쉽다.
7. 정리
이번 작업을 요약하면 크리에이터 기능을 단순 페이지 추가가 아니라 역할, 데이터 귀속, 검색, 라이브 상태, 정산 기준을 함께 맞추는 작업으로 다뤘다. 특히 랭킹과 정산처럼 나중에 데이터가 쌓이면 수정하기 어려운 부분은 초기에 기준을 명확히 잡는 것이 중요하다.
다음 단계에서는 실제 사용자 시나리오를 기준으로 검증할 필요가 있다. 크리에이터 승인, 프로필 노출, 라이브 토글, OBS 표시, 판매 발생, 랭킹 반영까지 한 번에 이어지는 플로우를 확인해야 한다.
'프로젝트 > HOTSPOT' 카테고리의 다른 글
| [HOTSPOT] 2026.06.28 - 서비스 기능 개선과 버그 수정을 실제 프로젝트에 적용한 과정 (0) | 2026.06.28 |
|---|---|
| [HOTSPOT] 2026.06.22 - 매니저와 크리에이터 정산 내역 표시 개선을 실제 프로젝트에 적용한 과정 (0) | 2026.06.22 |
| [HOTSPOT] 2026.06.21 - 서비스 기능 개선과 버그 수정을 실제 프로젝트에 적용한 과정 (0) | 2026.06.21 |
| [HOTSPOT] 2026.06.20 - 서비스 기능 개선과 버그 수정을 실제 프로젝트에 적용한 과정 (0) | 2026.06.20 |
| [HOTSPOT] 2026.06.19 - 랭킹 귀속 설계를 실제 프로젝트에 적용한 과정 (0) | 2026.06.19 |