- 원작 엔티티/레포지토리/관리자 API 구축(이미지 S3 업로드 포함)
- 캐릭터-원작 연관관계 및 관리자에서 배정/해제 API 제공
- 소프트 삭제(`isDeleted`) 도입 및 조회/수정/배정 로직에서 삭제 항목 필터링
- 컨트롤러-레포지토리 직접 접근 제거, `AdminOriginalWorkService`로 DB 접근 캡슐화
- 캐릭터 등록/수정에서 `originalWorkId` 지원 및 외부 API 업데이트 조건 분리
- ChatCharacterService.getPopularCharacters()에 @Cacheable 추가
- 키: popular-chat-character:<windowStartEpoch>:<limit>
- 윈도우(매일 20:00 UTC) 전환 시 자동으로 신규 키 사용 → 전일 순위 캐시와 분리 보장
Why: 동일 윈도우 내 반복 요청의 DB 부하를 줄이고, 경계 전환 시 자연스러운 캐시 갱신을 보장.
- 집계 기준을 "채팅방 전체 메시지 수"로 변경하여 캐릭터별 인기 순위 산정
- Querydsl `PopularCharacterQuery` 추가: chat_message → chat_participant(CHARACTER) → chat_character 조인
- 시간 경계: UTC 20:00 기준 [windowStart, nextBoundary) 구간 사용(배타적 종료 `<`)
- `ChatCharacterService.getPopularCharacters`에 @Cacheable 적용
- cacheNames: `popularCharacters_24h`
- key: `RankingWindowCalculator.now('popular-chat-character').cacheKey`
- 상위 20개 기본, `loadCharactersInOrder`로 랭킹 순서 보존
- `RankingWindowCalculator`: 경계별 동적 키 생성(`popular-chat-character:{windowStartEpoch}`) 및 윈도우 계산
- `RedisConfig`: 24시간 TTL 캐시 `popularCharacters_24h` 추가(문자열/JSON 직렬화 지정)
- `ChatCharacterController`: 메인 API에 인기 캐릭터 섹션 연동
WHY
- 20시(UTC) 경계 변경 시 키가 달라져 첫 조회에서 자동 재집계/재캐싱
- 방 전체 참여도를 반영해 보다 직관적인 인기 지표 제공
- 캐시(24h TTL)로 DB 부하 최소화, 경계 전환 후 자연 무효화
- 비활성(삭제) 큐레이션을 목록에서 제외: findByIsActiveTrueOrderBySortOrderAsc 사용
- 리스트 항목에 characterCount 추가 및 DB GROUP BY + COUNT로 직접 집계
- CharacterCurationMappingRepository: 집계용 프로젝션(CharacterCountPerCuration)과 countActiveCharactersByCurations 쿼리 추가
- CharacterCurationAdminService: listAll에서 집계 결과를 활용해 characterCount 매핑 (대량 엔티티 로딩 제거)
- CharacterCurationRepository: findMaxSortOrder 쿼리로 신규 등록 정렬 순서 계산에 활용
- 컨트롤러: 캐릭터 리스트 응답 DTO(CharacterCurationCharacterItemResponse) 사용, 이미지 URL은 CloudFront host + imagePath로 조립
- 왜: 기존에는 추가 정보(memories, personalities, backgrounds, relationships) 수정 시 전체 삭제 후 재생성되어 변경 누락/DB 오버헤드가 발생함
- 무엇:
- Memory/Personality/Background 값 필드(content/description/emotion)를 var로 전환해 in-place 업데이트 허용
- 서비스 레이어에 증분 업데이트 로직 적용
- 요청에 없는 항목만 제거, 기존 항목은 값만 갱신, 신규 키만 추가
- relationships는 personName+relationshipName 복합 키 매칭(keyOf)으로 필드만 갱신
- ChatCharacter 컬렉션에 orphanRemoval=true 설정하여 iterator.remove 시 고아 삭제 보장
- updateChatCharacterWithDetails에서 clear/add 제거 → 증분 업데이트 메서드 호출로 변경
- 효과: DELETE+INSERT 제거로 성능 개선, ID/createdAt 유지로 감사 추적 용이, 데이터 정합성 향상
- CharacterCuration/CharacterCurationMapping 엔티티 추가
- 리포지토리/서비스(조회·관리) 구현
- 관리자 컨트롤러에 등록/수정/삭제/정렬/캐릭터 추가·삭제·정렬 API 추가
- 앱 메인 API에 큐레이션 섹션 노출
- 정렬/소프트 삭제/활성 캐릭터 필터링 규칙 적용
- /api/chat/character/image/my-list 엔드포인트 추가
- 로그인/본인인증 체크
- 캐릭터 프로필 이미지를 리스트 맨 앞에 포함
- 보유 이미지(무료 또는 구매 이력 존재)만 노출
- CloudFront 서명 URL 발급로 접근 제어
- 페이징 로직 개선
- 기존: 전체 조회 후 메모리에서 필터링/슬라이싱
- 변경: QueryDSL로 DB 레벨에서 보유 이미지만 오프셋/리밋 조회
- 프로필 아이템(인덱스 0) 포함을 고려하여 owned offset/limit 계산
- 빈 페이지 요청 시 즉시 빈 결과 반환
- Repository
- CharacterImageQueryRepository + Impl 추가
- findOwnedActiveImagesByCharacterPaged(...) 구현
- 구매 이력: CHAT_MESSAGE_PURCHASE, CHARACTER_IMAGE_PURCHASE만 인정, 환불 제외
- 활성 이미지, sortOrder asc, id asc 정렬 + offset/limit
- Service
- getCharacterImagePath(characterId) 추가
- pageOwnedActiveByCharacterForMember(...) 추가
- Controller
- my-list 응답 스키마는 list와 동일하게 totalCount/ownedCount/items 유지
- 페이지 사이즈 상한 20 적용, 5분 만료 서명 URL
- 삭제 API: 본인 댓글에 대해 soft delete 처리
- 신고 API: 신고 내용을 그대로 저장하는 CharacterCommentReport 엔티티/리포지토리 도입
- Controller: 삭제, 신고 엔드포인트 추가 및 인증/본인인증 체크
- Service: 비즈니스 로직 구현 및 예외 처리 강화
왜: 캐릭터 댓글 관리 기능 요구사항(삭제/신고)을 충족하기 위함
무엇: 엔드포인트, 서비스 로직, DTO 및 JPA 엔티티/리포지토리 추가
- 캐릭터 댓글 엔티티/레포지토리/서비스/컨트롤러 추가
- 댓글 작성 POST /api/chat/character/{characterId}/comments
- 답글 작성 POST /api/chat/character/{characterId}/comments/{commentId}/replies
- 댓글 목록 GET /api/chat/character/{characterId}/comments?limit=20
- 답글 목록 GET /api/chat/character/{characterId}/comments/{commentId}/replies?limit=20
- DTO 추가/확장
- CharacterCommentResponse, CharacterReplyResponse, CharacterCommentRepliesResponse, CreateCharacterCommentRequest
- 캐릭터 상세 응답(CharacterDetailResponse) 확장
- latestComment(최신 댓글 1건) 추가
- totalComments(전체 활성 댓글 수) 추가
- 성능 최적화: getReplies에서 원본 댓글 replyCount 계산 시 DB 카운트 호출 제거
- toCommentResponse(replyCountOverride) 도입으로 원본 댓글 replyCount=0 고정
- 공통 검증: 로그인/본인인증/빈 내용 체크, 비활성 캐릭터/댓글 차단
WHY
- 캐릭터 상세 화면에 댓글 경험 제공 및 전체 댓글 수 노출 요구사항 반영
- 답글 조회 시 불필요한 카운트 쿼리 제거로 DB 호출 최소화
- ChatRoomService.listMyChatRooms 사용, 최근 순 최대 10개 노출
- 방 title/imageUrl을 그대로 사용해 UI/데이터 일관성 유지
- 비로그인 사용자는 빈 배열 반환
refactor(dto): RecentCharacter.characterId → roomId로 변경
- ChatCharacterRelationship 엔티티를 personName, relationshipName, description(TEXT), importance, relationshipType, currentStatus로 변경
- ChatCharacter.addRelationship 및 Service 메서드 시그니처를 새 스키마에 맞게 수정
- 등록/수정 플로우에서 relationships 매핑 로직 업데이트
- Admin 상세 응답 DTO(RelationshipResponse) 및 매핑 업데이트
- 전체 빌드 성공
- 상세 페이지 정보 강화 및 탐색성 향상을 위해 응답 필드를 확장
- CharacterDetailResponse에 originalTitle, originalLink, characterType, others 추가
- OtherCharacter DTO 추가 (characterId, name, imageUrl, tags)
- 공유 태그 기반으로 현재 캐릭터를 제외한 랜덤 10개 캐릭터 조회 JPA 쿼리 추가
- ChatCharacterRepository.findRandomBySharedTags(@Query, RAND 정렬, 페이징)
- 서비스 계층에 getOtherCharactersBySharedTags 추가 및 태그 지연 로딩 초기화
- 컨트롤러에서:
- others 리스트를 조회/매핑하여 응답에 포함
- originalTitle, originalLink, characterType을 응답에 포함
- ChatCharacter 엔티티에 originalTitle, originalLink(Nullable), characterType(Enum) 필드 추가
- characterType: CLONE | CHARACTER (기본값 CHARACTER)
- 원작/원작 링크는 빈 문자열 대신 null 허용으로 저장
- Admin DTO(Register/Update)에 originalTitle, originalLink, characterType 필드 추가
- 등록 API에서 외부 API 요청 바디에 3개 필드(originalTitle, originalLink, characterType) 제외 처리
- 수정 API에서 3개 필드만 변경된 경우 외부 API 호출 생략하고 DB만 업데이트
- hasChanges: 외부 API 대상 필드 변경 여부 판단(3개 필드 제외)
- hasDbOnlyChanges: 3개 필드만 변경된 경우 처리 분기
- Service 계층에 필드 매핑 및 Enum 파싱 추가
- createChatCharacter / createChatCharacterWithDetails에 originalTitle/originalLink/characterType 반영
- 이름 중복 검증 로직 유지, isActive=false 비활성화 이름 처리 로직 유지
- 관계 스키마를 name, relationShip 구조로 일원화
- Admin/사용자 컨트롤러 조회 응답에서 관계를 객체로 반환하도록 수정
- 등록/수정 요청 DTO에 ChatCharacterRelationshipRequest(name, relationShip) 추가
- 서비스 계층 create/update/add 메소드 시그니처 및 매핑 로직 업데이트
- description 한 줄 소개 사용 전제 하의 관련 사용부 점검(엔티티 컬럼 구성은 기존 유지)
왜: 기존에는 채팅방 미구현으로 최근 대화 리스트를 빈 배열로 응답했음. 채팅방/메시지 기능이 준비됨에 따라 실제 최근 대화 캐릭터를 노출해야 함.
무엇:
- repository: findRecentCharactersByMember JPA 쿼리 추가 (채팅방/참여자/메시지 조인, 최신 메시지 기준 정렬)
- service: getRecentCharacters(member, limit) 구현 (member null 처리 및 페이징 적용)
- controller: /api/chat/character/main에서 인증 사용자 기준 최근 캐릭터 최대 10개 반환