13 KiB
13 KiB
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: 실제 사람 MemberAI_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 = CREATORmemberKind = AI_CHARACTERemail = nullpassword = ""nickname은 기본적으로ChatCharacter.name기준profileImage는 기본적으로ChatCharacter.imagePath기준introduce는 기본적으로ChatCharacter.description기준
- AI 캐릭터용 Member의
nickname,profileImage,introduce는 기존 콘텐츠/라이브/커뮤니티/후원/정산/알림/팔로우/AGENT 소속 화면에서 별도ChatCharacterJOIN 없이 표시하기 위한 스냅샷이다. - 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 캐릭터 표시 정보를 조회할 때 별도
ChatCharacterJOIN을 추가하지 않는다.
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_idnullable 추가chat_character.creator_member_idFK 및 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 nullrow가 0건인지 확인한다.chat_character.creator_member_id를NOT NULL로 변경한다.
10. Metrics
- 기존
ChatCharacter중creator_member_id누락 0건 memberKind = AI_CHARACTER이면서role != CREATOR인 Member 0건memberKind = AI_CHARACTERMember 로그인 성공 0건memberKind = AI_CHARACTERMember 대상 DM 생성 성공 0건- 기존 사람 크리에이터의 DM, 콘텐츠 등록, 채널 후원 흐름 회귀 실패 0건
11. Open Questions
- AI 캐릭터용 콘텐츠/라이브/커뮤니티 등록 운영 흐름은 이번 범위에서 구현하지 않으므로, 후속 범위에서
chatCharacterId기반 대리 생성 API 정책을 별도로 정해야 한다.