docs(aicharacter): 크리에이터 연결 계획을 추가한다

This commit is contained in:
2026-06-12 00:12:17 +09:00
parent 39025fc3f3
commit 685209d47d
3 changed files with 704 additions and 0 deletions

View File

@@ -0,0 +1,208 @@
# PRD: AI 캐릭터 크리에이터 기능 최소 연결
## 1. Overview
`ChatCharacter`가 기존 크리에이터 기능을 최소 변경으로 사용할 수 있도록, 모든 `ChatCharacter``Member(role = CREATOR)`와 1:1로 연결하고 실제 사람 Member와 AI 캐릭터용 Member를 `memberKind`로 구분한다.
---
## 2. Problem
- 현재 `ChatCharacter`는 AI 대화 주체로만 동작하고, 라이브/콘텐츠/커뮤니티/채널 후원/정산/알림 등 크리에이터 기능의 주체가 될 수 없다.
- 기존 크리에이터 기능은 대부분 `Member(role = CREATOR)``member.id` 기반 `creatorId`를 전제로 구현되어 있다.
- `ChatCharacter`를 독립 소유자로 직접 도입하면 콘텐츠, 라이브, 후원, 정산, 랭킹, 알림, 차단, 팔로우 등 넓은 범위의 소유자 모델 변경이 필요하다.
- 이번 변경은 기존 `Member` 기반 크리에이터 기능을 유지하면서, AI 캐릭터가 크리에이터 기능을 사용할 수 있는 최소 연결 구조가 필요하다.
---
## 3. Goals
- `Member``MemberKind`를 추가해 실제 사람 Member와 AI 캐릭터용 Member를 구분한다.
- 모든 기존 `ChatCharacter`에 대응되는 `Member(role = CREATOR, memberKind = AI_CHARACTER)`를 생성하고 1:1로 연결할 수 있는 마이그레이션 SQL을 준비한다.
- 신규/기존 `ChatCharacter`는 크리에이터 기능 주체인 `creatorMember`를 가진다.
- `memberKind = AI_CHARACTER`인 Member는 로그인할 수 없도록 차단한다.
- `memberKind = AI_CHARACTER`인 Member는 유저-크리에이터 DM 생성 대상이 될 수 없도록 차단한다.
- `memberKind = AI_CHARACTER`인 Member는 로그인과 DM을 제외하고 `Member(role = CREATOR)`가 사용할 수 있는 기존 크리에이터 기능을 사용할 수 있어야 한다.
- AI 캐릭터용 Member의 표시 정보는 연결된 `ChatCharacter`의 이름, 프로필 이미지, 소개를 스냅샷으로 복사해 기존 Member 기반 화면과 쿼리를 재사용한다.
- 기존 사람 크리에이터의 콘텐츠/라이브/커뮤니티/채널 후원/정산/알림 동작은 유지한다.
---
## 4. Non-Goals
- 이번 범위에서 `ChatCharacter``Member`와 동급의 별도 소유자 타입으로 만들지 않는다.
- 이번 범위에서 `creator_identity` 같은 공통 크리에이터 소유자 테이블을 도입하지 않는다.
- 이번 범위에서 공개 API의 기존 `creatorId = member.id` 의미를 변경하지 않는다.
- 이번 범위에서 크리에이터 검색 결과 카테고리 개편은 구현하지 않는다.
- 이번 범위에서 `Member:ChatCharacter = 1:N` 관계를 허용하지 않는다.
- 이번 범위에서 AI 캐릭터용 Member의 직접 로그인, 직접 크리에이터 관리자 접속, 직접 DM 기능은 허용하지 않는다.
- 이번 범위에서 AI 캐릭터용 콘텐츠/라이브/커뮤니티 대리 생성 API를 새로 설계하지 않는다.
- 이번 범위에서 기존 정산 산식, 정산 비율, 랭킹 점수 산식은 변경하지 않는다.
- 이번 범위에서 AI 캐릭터용 Member를 정산 관리자 화면에서 사람 크리에이터와 별도 목록 또는 별도 필터로 분리하지 않는다.
---
## 5. Target Users
- 일반 사용자: AI 캐릭터와 AI 대화를 하고, AI 캐릭터 채널에 후원하거나 AI 캐릭터 콘텐츠를 소비하는 회원
- 사람 크리에이터: 필요 시 자신의 `Member`에 연결된 `ChatCharacter`를 통해 AI 대화 기능을 제공하는 크리에이터
- 운영/정산 담당자: AI 캐릭터용 Member를 기존 크리에이터 정산 흐름에서 식별하고 처리해야 하는 담당자
---
## 6. User Stories
- 사용자는 모든 활성 `ChatCharacter`와 AI 대화를 시작하고 싶다.
- 사용자는 AI 캐릭터 채널에도 기존 크리에이터 채널처럼 채널 후원을 하고 싶다.
- 사용자는 AI 캐릭터가 업로드한 콘텐츠를 기존 콘텐츠와 같은 방식으로 보고 싶다.
- 시스템은 AI 캐릭터용 Member가 실제 사람 계정처럼 로그인하거나 DM 대상이 되는 것을 막고 싶다.
- 운영자는 사람 크리에이터와 AI 캐릭터용 크리에이터 Member를 데이터에서 명확히 구분하고 싶다.
---
## 7. Core Features
### Feature A. `MemberKind` 도입
#### Requirements
- `Member``memberKind` 필드를 추가한다.
- `MemberKind` 값은 최소 다음 2개를 가진다.
- `HUMAN`: 실제 사람 Member
- `AI_CHARACTER`: AI 캐릭터 기능을 위해 생성된 내부 크리에이터 Member
- `memberKind``NOT NULL`이며 기본값은 `HUMAN`이다.
- 기존 모든 Member 데이터는 DDL 기본값에 의해 `memberKind = HUMAN`이 된다.
- 일반 회원가입, 관리자, 에이전트, 콘텐츠 관리자 등 실제 사람 계정은 `memberKind = HUMAN`을 사용한다.
- `memberKind = AI_CHARACTER`인 Member도 `role = CREATOR`를 가진다.
- 크리에이터 기능 가능 여부는 기존처럼 기본적으로 `role = CREATOR`를 기준으로 유지한다.
- 사람 크리에이터 전용 기능 가능 여부는 `role = CREATOR``memberKind = HUMAN`을 함께 기준으로 판단한다.
- `memberKind = AI_CHARACTER`인 Member는 로그인과 DM을 제외한 팔로우, 채널 후원, 콘텐츠, 커뮤니티, 라이브, 정산, 알림 등 기존 CREATOR 기능의 대상이 될 수 있다.
#### Edge Cases
- `memberKind = HUMAN`만으로 사람 크리에이터 여부를 판단하면 안 되며, 반드시 `role = CREATOR` 조건을 함께 확인해야 한다.
- `memberKind = AI_CHARACTER`인 Member는 반드시 `role = CREATOR`여야 한다.
---
### Feature B. `ChatCharacter`와 `Member` 1:1 연결
#### Requirements
- `ChatCharacter`가 관계의 주인이며 `creatorMember`를 가진다.
- 관계는 초기에는 1:1로 제한한다.
- DB에는 `chat_character.creator_member_id`를 추가한다.
- `chat_character.creator_member_id``member.id`를 참조한다.
- `chat_character.creator_member_id`에는 unique 제약을 둔다.
- `ChatCharacter.creatorMember.role`은 반드시 `CREATOR`여야 한다.
- 기존 모든 `ChatCharacter`는 마이그레이션 후 `creatorMember`가 있어야 한다.
- 기존 `ChatCharacter` 중 실제 사람 크리에이터와 연결해야 하는 데이터는 이번 마이그레이션 대상에 없다고 본다.
- 기존 모든 `ChatCharacter`는 새 `Member(role = CREATOR, memberKind = AI_CHARACTER)`를 생성해 연결한다.
#### Edge Cases
- 이미 연결된 `ChatCharacter`에 중복 `creatorMember`가 배정되면 안 된다.
- 하나의 `Member`에 여러 `ChatCharacter`가 연결되면 안 된다.
- 비활성 `ChatCharacter`도 기존 데이터 정합성을 위해 `creatorMember` 연결 대상에 포함한다.
---
### Feature C. 기존 `ChatCharacter`용 Member 생성 마이그레이션
#### Requirements
- 운영 DB 반영용 MySQL 기준 DDL과 backfill SQL을 작성한다.
- 마이그레이션 SQL은 기존 `ChatCharacter`별로 AI 캐릭터용 `Member`를 생성할 수 있어야 한다.
- 생성되는 AI 캐릭터용 Member는 다음 정책을 따른다.
- `role = CREATOR`
- `memberKind = AI_CHARACTER`
- `email = null`
- `password = ""`
- `nickname`은 기본적으로 `ChatCharacter.name` 기준
- `profileImage`는 기본적으로 `ChatCharacter.imagePath` 기준
- `introduce`는 기본적으로 `ChatCharacter.description` 기준
- AI 캐릭터용 Member의 `nickname`, `profileImage`, `introduce`는 기존 콘텐츠/라이브/커뮤니티/후원/정산/알림/팔로우/AGENT 소속 화면에서 별도 `ChatCharacter` JOIN 없이 표시하기 위한 스냅샷이다.
- backfill 후 `chat_character.creator_member_id`가 없는 row가 0건인지 검증하는 SQL을 포함한다.
- 검증 완료 후 `chat_character.creator_member_id``NOT NULL`로 전환할 수 있어야 한다.
#### Edge Cases
- `ChatCharacter.name`이 중복되더라도 Member 생성이 가능해야 한다.
- AI 캐릭터용 Member의 로그인 차단은 `email/password` 값이 아니라 `memberKind = AI_CHARACTER` 정책으로 보장해야 한다.
- 기존 `ChatCharacter`의 사람 크리에이터 수동 매핑은 이번 범위에서 제공하지 않는다.
---
### Feature D. AI 캐릭터 표시 정보 동기화
#### Requirements
- AI 캐릭터용 Member의 표시 정보는 연결된 `ChatCharacter` 값을 기준으로 유지한다.
- `ChatCharacter.name``Member.nickname`에 동기화한다.
- `ChatCharacter.imagePath``Member.profileImage`에 동기화한다.
- `ChatCharacter.description``Member.introduce`에 동기화한다.
- `ChatCharacter` 생성 시 AI 캐릭터용 Member를 함께 생성하는 경우 같은 transaction 안에서 표시 정보를 복사한다.
- `ChatCharacter` 수정 시 연결된 AI 캐릭터용 Member의 표시 정보도 같은 transaction 안에서 갱신한다.
- `memberKind = AI_CHARACTER`인 Member의 표시 정보는 직접 수정 API가 아니라 `ChatCharacter` 생성/수정 흐름을 기준으로 관리한다.
#### Edge Cases
- 동기화 대상 `creatorMember`가 없으면 저장을 실패시켜 데이터 불일치를 막아야 한다.
- 연결된 `creatorMember.memberKind != AI_CHARACTER`인 경우, 사람 크리에이터의 프로필을 덮어쓰지 않도록 동기화 대상에서 제외하거나 별도 정책을 명확히 적용해야 한다.
- 기존 Member 기반 화면은 AI 캐릭터 표시 정보를 조회할 때 별도 `ChatCharacter` JOIN을 추가하지 않는다.
---
### Feature E. AI 캐릭터용 Member 로그인 차단
#### Requirements
- `memberKind = AI_CHARACTER`인 Member는 모든 일반 로그인 흐름에서 인증 성공 상태가 되면 안 된다.
- 크리에이터 관리자 로그인 흐름에서도 `memberKind = AI_CHARACTER`인 Member는 로그인할 수 없어야 한다.
- 소셜 로그인 또는 토큰 재발급 흐름에서 AI 캐릭터용 Member가 세션/토큰을 얻을 수 있는 경로가 있으면 차단한다.
- 차단 시 기존 인증 실패 응답 패턴을 우선 재사용한다.
- AI 캐릭터용 Member는 로그인에 사용하지 않으므로 `email``null`을 허용하고, `password`는 기존 소셜 회원 생성 패턴과 같이 빈 문자열을 사용할 수 있다.
- 로그인 차단은 `email/password` 값이 아니라 `memberKind = AI_CHARACTER` 정책으로 보장한다.
#### Edge Cases
- 기존 토큰을 이미 가진 AI 캐릭터용 Member가 있을 수 없도록 마이그레이션 시점과 배포 순서를 점검한다.
- 후속 범위에서 관리자/콘텐츠 관리자가 AI 캐릭터용 콘텐츠를 등록하더라도, AI 캐릭터용 Member 자체가 로그인하는 것은 허용하지 않는다.
---
### Feature F. AI 캐릭터용 Member DM 차단
#### Requirements
- 유저-크리에이터 DM 생성 대상이 `memberKind = AI_CHARACTER`이면 DM 방을 생성하지 않는다.
- 기존 사람 크리에이터는 `ChatCharacter` 연결 여부와 무관하게 DM이 가능해야 한다.
- DM 차단 기준은 `ChatCharacter` 연결 여부가 아니라 `Member.memberKind`이다.
#### Edge Cases
- `memberKind = HUMAN`인 사람 크리에이터가 `ChatCharacter`를 가진 경우에도 DM은 가능해야 한다.
- `memberKind = AI_CHARACTER`인 Member가 `role = CREATOR`이더라도 DM은 불가능해야 한다.
---
## 8. Technical Constraints
- Kotlin, Spring Boot 2.7.14, Java 17, Gradle Wrapper 구조를 유지한다.
- 기존 공개 API의 `creatorId` 의미는 이번 범위에서 변경하지 않는다.
- 기존 콘텐츠/라이브/커뮤니티/후원/정산 테이블의 소유자 컬럼은 `Member` 기준을 유지한다.
- `ChatCharacter``Member` 관계는 초기에는 `ChatCharacter` 단방향 `OneToOne`으로 구현한다.
- 운영 DB 반영용 DDL은 MySQL 기준으로 작성한다.
- DDL 컬럼에는 가능한 경우 `COMMENT`를 추가한다.
- `memberKind` 기반 정책 판단은 중복 분기를 줄이기 위해 정책 함수 또는 명확한 서비스 검증으로 모은다.
- 검색 결과 카테고리 개편은 이번 구현에서 제외하되, 향후 `memberKind`를 활용할 수 있도록 데이터 모델만 준비한다.
---
## 9. Data Migration Requirements
- Phase 1 DDL
- `member.member_kind``NOT NULL DEFAULT 'HUMAN'`으로 추가
- `chat_character.creator_member_id` nullable 추가
- `chat_character.creator_member_id` FK 및 unique index 추가
- Phase 2 backfill
- 기존 모든 `ChatCharacter`별로 AI 캐릭터용 `Member(role = CREATOR, memberKind = AI_CHARACTER)`를 생성한다.
- 생성된 Member를 `chat_character.creator_member_id`에 연결한다.
- Phase 3 검증 및 제약 강화
- `member_kind = 'AI_CHARACTER' and role <> 'CREATOR'` row가 0건인지 확인한다.
- `chat_character.creator_member_id is null` row가 0건인지 확인한다.
- `chat_character.creator_member_id``NOT NULL`로 변경한다.
---
## 10. Metrics
- 기존 `ChatCharacter``creator_member_id` 누락 0건
- `memberKind = AI_CHARACTER`이면서 `role != CREATOR`인 Member 0건
- `memberKind = AI_CHARACTER` Member 로그인 성공 0건
- `memberKind = AI_CHARACTER` Member 대상 DM 생성 성공 0건
- 기존 사람 크리에이터의 DM, 콘텐츠 등록, 채널 후원 흐름 회귀 실패 0건
---
## 11. Open Questions
- AI 캐릭터용 콘텐츠/라이브/커뮤니티 등록 운영 흐름은 이번 범위에서 구현하지 않으므로, 후속 범위에서 `chatCharacterId` 기반 대리 생성 API 정책을 별도로 정해야 한다.