Skip to content

[chore] prod 배포 v1.0.8 - #211

Merged
theminjunchoi merged 2 commits into
prodfrom
dev
Aug 28, 2026
Merged

[chore] prod 배포 v1.0.8#211
theminjunchoi merged 2 commits into
prodfrom
dev

Conversation

@theminjunchoi

Copy link
Copy Markdown
Collaborator

📌 개요

dev 에 쌓인 2건을 prod 로 올린다. 마이그레이션 1건(신규 테이블) 있고, API 는 하위 호환이다.

PR 내용
#208 계층 의존 방향 어긋난 곳 수정 및 코드 일관화
#210 백오피스에서 새벽 알림 발송 여부 확인

#208 은 내부 구조만 바꾼다. #210 이 사용자에게 닿는 동작을 하나 바꾸므로 아래에 따로 적는다.

⚠️ 이번 배포로 바뀌는 것

1. 04:30 리마인더가 회원마다 따로 나간다

전에는 대상 전원의 토큰을 모아 FCM 을 한 번 불렀다. 이제 회원마다 한 번씩 부른다.

바꾼 이유는 발송 결과를 대화방별로 남기기 위해서다. 한 번에 몰아 보내면 결과가 전원분 합계로만 돌아와서, 한 명이라도 성공하면 기기가 없던 회원의 방까지 '발송' 으로 기록된다.

  • 사용자가 받는 알림은 그대로다. 회원당 1회, 문구도 같다
  • FCM 호출 수가 대상 회원 수만큼 늘어난다. [fix] 메시지 하나만 보낸 대화방은 배치로 인한 카드가 영영 생기지 않는다 #205 조사 당시 로그 기준 대상이 한 자릿수(대상=7)라 부담은 없다고 봤다
  • 대가가 하나 있다: 중간에 터지면 부분 상태로 끝난다. 회원 k 에서 예외가 나면 앞선 회원은 알림을 받고 뒤는 통째로 빠진다. 전에는 예외가 곧 '아무도 못 받았다' 였으므로 결과 자체는 나아졌지만 성격이 달라졌다. 배치 로그의 대상=N명성공=M건 이 크게 벌어지면 이 경우다

2. 백오피스 '대화방별 사용량' 에 알림 칸 두 개가 생긴다

04:30 알림, 05:00 알림 컬럼이 붙는다. 값은 다섯 가지다.

표시
발송 FCM 이 성공을 돌려줬다
기기 없음 알림을 껐거나 앱을 지운 회원이라 보낼 기기가 없었다. 실패가 아니다
실패 FCM 이 실패를 돌려줬거나 발송 시도가 끊겼다
건너뜀 같은 회원의 다른 방으로 이미 같은 알림이 나갔다
빈칸 그 회차에 이 방이 대상이 아니었다

배포 직후에는 전부 빈칸이다. 이력을 남기기 시작한 것이 이번 배포라 과거 회차의 기록이 없다. 다음 새벽 배치(04:30, 05:00)부터 채워진다. 표 설명에도 그 사실을 적어 뒀다.

3. 백오피스 표의 줄바꿈이 사라진다

진행중, 삭제됨, 생성 배지와 헤더가 좁은 칸에서 두 줄로 접히던 것을 고쳤다. 기능 변화는 없다.

🗄️ 마이그레이션

V36__notification_log.sql 신규 테이블 하나뿐이다. 기존 테이블과 데이터는 건드리지 않는다.

CREATE TABLE notification_log (
    id, member_id, conversation_id, type, outcome, created_at
);
CREATE INDEX idx_notification_log_conversation ON notification_log (conversation_id, type, created_at);

빈 테이블 생성이라 즉시 끝나고, 실패해도 기존 스키마에 영향이 없다.

🌐 API

  • GET /api/admin/conversation-usage 응답에 reminderNotification, cardNotification 두 필드 추가(nullable). 기존 필드는 그대로라 클라이언트 영향 없음
  • 그 외 앱이 쓰는 API 는 변경 없다. [refactor] 계층 의존 방향 어긋난 곳 수정 및 코드 일관화 #208ErrorCode 에서 HttpStatus 를 떼어냈지만 에러 코드 36개의 상태 코드가 변경 전과 전부 동일한지 프로그램으로 대조해 확인했다

🔎 배포 후 확인

  1. notification_log 테이블이 생성됐는지
  2. 백오피스 '대화방별 사용량' 에 알림 칸 두 개가 뜨고 전부 빈칸인지
  3. 다음 04:30 배치 로그: 미종료 대화방 리마인더 완료: 대상=N명, 대화방=M개, 성공=..., 실패=... 에서 대상과 성공이 크게 벌어지지 않는지
  4. 다음 05:00 배치 이후 백오피스 표에 값이 채워지는지

💬 참고

이번 배포에 사용자 대상 신규 기능은 없다. 3번(줄바꿈)만 백오피스 화면에 보이고, 1번은 발송 방식이 바뀌었을 뿐 받는 알림은 같다.

* refactor: 검색 인덱스 생성을 도메인 밖으로 옮긴다

Message·Conversation 이 BlindIndexer 를 알지 않게 한다. applySearchIndex 가
인덱서 대신 완성된 인덱스 값을 받으므로, 엔티티는 "검색 인덱스 값을 보관한다"만
알고 그것이 HMAC 인지 무엇인지는 모른다. domain -> global.crypto import 가 사라진다.

인덱스를 만드는 두 리스너는 JPA 라이프사이클 훅 + HMAC 계산이라 도메인이 아니므로
conversation/search 로 옮긴다. @EntityListeners 는 클래스 참조라 패키지가 달라도
그대로 동작한다.

* refactor: 검색 추상화에서 Port 네이밍을 걷어낸다

ConversationSearchPort -> ConversationSearcher,
BlindIndexConversationSearch -> BlindIndexConversationSearcher 로 바꾸고
주입 필드명 searchPort 와 "포트 구현" 표현도 함께 정리한다. 헥사고날 용어를 쓰지 않는다.

* refactor: ErrorCode 에서 HTTP 상태 코드를 떼어낸다

ErrorCode 는 도메인이 그대로 참조하는데(Nickname·ConversationTitle·FcmToken·
ExcludedEmotionTypes·Card·Conversation) HttpStatus 를 필드로 들고 있어서, 닉네임
검증 규칙까지 스프링 웹 타입에 묶여 있었다.

ErrorCode 는 에러의 성격만 ErrorKind 로 말하고, HTTP 상태 코드로의 번역은 웹 계층의
httpStatusOf 가 맡는다. when 이 exhaustive 라 ErrorKind 를 추가하면 상태 코드를 정하지
않고는 컴파일되지 않는다.

에러 코드 36개의 상태 코드는 변경 전과 전부 동일하다.

* refactor: 백오피스 집계 서비스가 웹 응답 DTO 를 만들지 않게 한다

UsageStatsService·QualityStatsService 가 admin/controller/dto 의 Response 를 직접
조립해 반환하고 있었다. 서비스가 웹 응답 포맷을 알면 필드명·Swagger 스키마가 바뀔 때마다
집계 코드가 따라 바뀐다.

두 서비스는 UsageStats·QualityStats(및 DailyActivity·DailyGeneration·EmotionCount)를
반환하고, Response 로의 변환은 컨트롤러가 한다. ConversationUsage 가 이미 쓰던 방식과 같다.

EmotionCountResponse 가 card/repository 의 EmotionCountProjection 을 알던 것도 없앤다.
컨트롤러 DTO 가 서비스를 건너뛰고 리포지토리 프로젝션을 직접 참조하고 있었다.

TokenUsageResponse 는 tokenlimit 의 TokenUsage 대신 컨트롤러에서 값을 받아 만든다.

* refactor: 모듈이 다른 모듈의 리포지토리를 직접 잡지 않게 한다

admin·monitoring·tokenlimit·notification·card 가 남의 모듈 리포지토리를 그대로
주입받아 쓰고 있었다. 이러면 쿼리 하나를 고칠 때 어느 모듈이 깨지는지 알 수 없고,
주인 모듈이 자기 저장 구조를 바꿀 자유를 잃는다.

읽기는 주인 모듈이 창구를 연다.
- conversation/service/ConversationReadService
- card/service/CardReadService
- monitoring/service/GenerationLogReadService
- member 는 이미 있는 MemberService 에 countSignupsBetween 을 더한다

카드 생성이 대화방 상태를 바꾸던 부분은 conversation/service/ConversationCardStateService
로 옮긴다. 어느 상태에서 어느 상태로 갈 수 있는지(SKIPPED 포함 CAS 대상)를 카드 모듈이
알고 있을 이유가 없다. 대화방 소유·종료 판정도 대화 모듈이 한 번만 정의한다.

인터페이스 프로젝션(EmotionCountProjection·ConversationSenderCountProjection)도 모듈 밖으로
내보내지 않는다. 프로젝션은 쿼리 모양에 딸린 것이라 밖으로 새면 쿼리를 못 바꾼다.

* test: 계층 의존 방향과 검색 인덱스 채우기를 테스트로 고정한다

LayerDependencyTest 는 이번에 고친 규칙들을 코드로 남긴다. 도메인이 인프라를 모른다,
서비스가 컨트롤러를 모른다, 컨트롤러가 리포지토리를 건너뛰지 않는다, 모듈이 남의
리포지토리를 직접 잡지 않는다, global 이 기능 모듈을 모른다, 에러 코드가 HTTP 를 모른다,
Port·Adapter 네이밍을 쓰지 않는다. 새 의존성 없이 소스의 import 만 본다.

SearchIndexFillIntegrationTest 는 메시지를 저장하는 세 경로(사용자 메시지, 캐릭터 댓글·
티키타카, 유저 답글 재응답)와 제목 rename 에서 인덱스가 실제로 채워지는지 확인한다.
리스너를 도메인 밖으로 옮긴 뒤에도 그 보장이 그대로여야 한다.

두 테스트 모두 규칙을 일부러 되돌려 실제로 실패하는 것을 확인했다.

@EntityListeners 참조는 규칙에서 예외로 둔다. @convert 와 같은 JPA 선언이고 엔티티가
리스너를 호출하는 것이 아니다(근거는 EncryptedStringConverter KDoc).

global/exception 이 스프링 웹을 모르도록 GlobalExceptionHandler 와 httpStatusOf 를
global/web 으로 옮긴다.

* refactor: 읽기 창구 패턴을 member 에도 맞추고 대화 설정을 밖으로 흘리지 않는다

D 에서 세운 규칙(다른 모듈이 읽어갈 때는 주인 모듈의 XxxReadService 를 거친다)을
member 만 지키지 않고 있었다. MemberService 에 쓰기와 밖에서 읽는 것이 섞여 있어,
getById·search·getStats·countSignupsBetween 을 MemberReadService 로 옮긴다.
MemberService 는 create·updateNickname·withdraw 만 남고 읽기는 창구에 위임한다.

QualityStatsService 가 ConversationProperties.pendingGenerationTimeout 을 직접 읽어
'막힌 PENDING' 기준 시각을 계산하고 있었다. 그 기준은 대화 모듈이 정하는 값이라,
부르는 쪽이 계산하면 정리 스케줄러가 쓰는 기준과 조용히 어긋날 수 있다.
countCommentsStuckBefore(before) 를 countStuckPendingComments() 로 바꿔 대화 모듈이
자기 기준으로 판단하게 한다.

* chore: 쓰이지 않는 import 를 제거한다

리팩터링으로 참조가 사라졌는데 남아 있던 것들이다. ktlint 1.8 의 standard 룰셋에는
no-unused-imports 가 없어서 빌드가 잡아주지 못한다.

* refactor: 서비스를 읽기·쓰기가 아니라 목적으로 가른다

XxxReadService 는 기술 축이라, 새 기능마다 "이건 읽기인가"를 물어야 하는데 유스케이스
서비스에도 조회가 있어서 답이 갈렸다. 실제로 member 만 읽기·쓰기 축으로, 나머지는
모듈 안·밖 축으로 갈라져 있었다.

목적으로 가르면 이름이 곧 배치 규칙이 된다. "무엇을 위한 기능인가"만 물으면 된다.

- ConversationReadService(15) 를 셋으로 나눈다
  - ConversationStatsService: 얼마나 있는지 센다(백오피스 집계·모니터링 게이지)
  - ConversationCardGenerationService: 카드 생성이 대화방에 요구하는 것
    (기존 ConversationCardStateService 를 개명하고 카드 생성용 조회 셋을 흡수)
  - ConversationService: 대화방 삭제(카드 삭제에 딸린 것 포함)와 미종료 방 주인 조회
- CardReadService -> CardStatsService
- GenerationLogReadService -> GenerationLogStatsService
- MemberReadService 는 없앤다. getById·search 는 회원 유스케이스라 MemberService 로
  돌리고, 집계 둘만 MemberStatsService 로 뺀다

getOwnedConversation 이 ConversationService 와 조회 창구 양쪽에 중복돼 있었다.
ConversationService 것을 공개해 하나로 만들고 카드 쪽은 위임한다.

LayerDependencyTest 에 이름 규칙을 더한다. Read·WriteService 로 되돌아가면 실패한다.
되돌려서 실제로 잡히는 것을 확인했다.

* fix: 자체 리뷰에서 나온 세 건을 고친다

1. LayerDependencyTest 가 소스를 하나도 못 찾으면 실패시킨다. MAIN_SOURCE 가
   상대경로라 작업 디렉터리가 프로젝트 루트가 아니면 빈 리스트가 되는데, 그때 규칙
   여덟 개가 전부 "위반 0건"으로 통과해 버린다. 경로를 깨뜨려 확인했고, 고친 뒤에는
   여덟 개가 모두 실패한다.

2. ErrorKind 와 ErrorCode 의 KDoc 링크가 옮기기 전 위치(global.response.httpStatusOf)를
   가리키고 있었다. 실제 위치는 global.web 이다. KDoc 링크는 깨져도 컴파일이 통과한다.

3. 쓰이지 않는 import 세 개를 지운다. getOwnedConversation 을 위임으로 바꾸고
   deleteForCardRemoval 을 옮기면서 생긴 것들이다.

* fix: 리뷰 반영, 검색 인덱스 규칙과 인덱싱 책임을 바로잡는다

1. LayerDependencyTest 가 #191 이 지목한 바로 그 위반을 못 잡고 있었다.
   OUTER_LAYERS 에 crypto 가 없어서 domain -> global.crypto 가 규칙 밖이었다.
   EncryptedStringConverter 를 남기려고 뺀 것인데 같은 패키지의 BlindIndexer 까지
   함께 빠졌다. 앞서 "되돌려서 잡히는지" 확인할 때 repository import 로 시험해
   다른 위반을 검증하고 넘어간 것이 원인이다.

   crypto 를 OUTER_LAYERS 에 넣고, @convert 도 @EntityListeners 와 같은 JPA 선언이므로
   Converter 를 예외에 더한다. #191 이전 모양으로 되돌려 실제로 실패하는 것을 확인했다.

2. applySearchIndex 가 완성된 값을 받으면서 리스너가 conversation.title?.value 를
   알게 됐다. 인덱싱 대상이 바뀌면 엔티티와 리스너를 같이 고쳐야 하고 한쪽만 고치면
   조용히 어긋난다. dev 시절 리스너는 그것을 몰랐으므로 결합이 없어진 게 아니라
   옮겨간 것이었다.

   (String) -> String? 을 받는다. BlindIndexer import 는 그대로 사라지고, 무엇을
   인덱싱할지는 엔티티가, 어떻게 만들지는 리스너가 각자 안다.

3. 그 메서드는 internal 로 좁힌다. "직접 부를 일은 없다"를 KDoc 으로 부탁하던 자리를
   컴파일러가 대신 막는다. 부르는 쪽은 같은 모듈의 리스너뿐이다.
* fix: 백오피스 배지가 좁은 칸에서 줄바꿈되지 않게 한다

상태(진행중, 삭제됨)와 카드(생성) 배지가 두 줄로 접혀 행 높이가 들쭉날쭉했다.
Badge 는 어느 자리에서도 줄바꿈될 이유가 없으므로 기본 클래스에 넣는다.

* feat: 새벽 알림이 나갔는지 백오피스에서 대화방별로 본다

지금까지 FCM 발송 이력을 어디에도 남기지 않아 "알림이 나갔는지"를 서버 로그로만 확인할
수 있었다. 로그는 회원 단위 집계라 "이 방 때문에 대상이었는가"를 답하지 못한다.

notification_log 에 알림 1건이 대화방 하나에 대해 어떻게 끝났는지 남긴다. 발송은 회원
단위인데 표는 대화방 단위라, 발송 한 번이 방 여러 개를 커버하면 방마다 한 줄씩 남기고
같은 결과를 적는다.

결과를 성공, 실패 둘로 두지 않는다. 알림을 끈 회원(NO_DEVICE)과 같은 회원의 다른 방으로
이미 나가서 건너뛴 것(SKIPPED)은 실패가 아닌데, 셋을 뭉치면 백오피스에서 '안 갔다'로만
보여 대응할 것과 아닌 것이 구분되지 않는다. 기록이 아예 없으면 그 회차에 대상이 아니었다는
뜻이라 표에서 빈칸이다.

04:30 리마인더 조회가 회원 id 대신 (대화방, 회원) 을 돌려주게 바꿨다. 회원당 한 번만
보내는 중복 제거는 발송하는 쪽으로 옮겼다.

* fix: 표 헤더와 생성일도 줄바꿈되지 않게 한다

알림 컬럼 두 개를 더하면서 폭이 밀려 헤더가 접혔다("05:00 알/림", "캐릭/터").
헤더 라벨은 어느 표에서도 접힐 이유가 없으므로 TableHead 기본 클래스에 넣는다.

같은 이유로 좁아진 생성일도 "2026. 08. / 27. 12:12" 로 어색하게 끊겼다. 날짜와 시각을
한 줄로 두고, 넘치면 이미 있는 가로 스크롤이 받는다.

* fix: 알림 발송 결과를 회원별로 정확히 기록한다

CodeRabbit 리뷰에서 나온 두 건이다. 둘 다 발송 이력이 사실과 다르게 남는 문제라,
"이 방 때문에 알림이 갔는가"를 보여주려던 목적 자체를 깨뜨린다.

1. 04:30 리마인더가 전원에게 한 번에 보내고 그 합계 하나를 모든 방에 적어 넣었다.
   한 명이라도 성공하면 기기가 없던 회원의 방까지 '발송'으로 남는다. 회원마다 따로
   보내 자기 결과로 기록한다. FCM 왕복이 늘지만 새벽 배치이고 대상은 수십 명 단위다.

2. CardCreatedNotifier 가 예외를 PushSendResult.none() 으로 삼켜서, 토큰 조회나 정리가
   끊긴 장애가 '기기 없음'(알림을 끈 회원이라는 정상 상태)으로 기록됐다. none() 과
   구분되는 failed() 를 두고 그것을 돌려준다. 배치 집계에서도 실패가 세어진다.

NotificationLogRecorderTest 를 새로 두어 결과 네 가지의 매핑을 고정한다. 세 항목 모두
되돌려서 실제로 실패하는 것을 확인했다.

* refactor: 자체 리뷰에서 나온 네 건을 고친다

1. admin 이 notification 리포지토리를 직접 잡고 있었다. #208 이 "모듈은 다른 모듈의
   리포지토리를 직접 잡지 않는다"를 규칙으로 넣는데, dev 의 기존 위반 19건은 그 PR 이
   전부 고치고 이 PR 만 20번째를 더하고 있었다. #208 의 규칙 파일을 이 브랜치에 붙여
   실제로 걸리는 것을 확인했다.

   #208 이 세운 목적 축대로 notification/service/NotificationLogStatsService 를 둔다.
   엔티티도 밖으로 내보내지 않고 결과값만 돌려준다.

2. 회원마다 따로 보내도록 바꾸면서 중간에 터지면 부분 상태로 끝나게 됐는데, KDoc 은
   전원에게 한 번에 보내던 때의 설명("예외가 나가도 그 회차가 끝날 뿐이다") 그대로였다.
   실제 동작을 적고 테스트로 고정한다.

3. 대화방별 사용량 표가 빈 값을 알림 칸은 하이픈, 나머지 칸은 em dash 로 그려 한 행에
   두 기호가 나란히 보였다. em dash 를 쓰지 않기로 했으므로 하이픈으로 맞춘다.

4. 새로 쓴 주석에 남은 가운뎃점 하나를 고친다.

* style: 손보는 파일의 em dash 와 가운뎃점을 걷어낸다

두 문자를 쓰지 않기로 했고, 기존 코드는 그 파일을 손볼 때 함께 고치기로 했다. 이 PR 이
건드리는 11개 파일이 대상이다.

가운뎃점은 자리마다 쉼표인지 '와/과'인지 달라 기계적으로 바꾸지 않고 표현마다 정했다.
em dash 는 대부분 뒤에 완결된 문장이 오는 자리라 마침표로 끊었고, 그렇게 해서 어색해진
다섯 곳은 문장을 다시 썼다.

DailyAutoCardScheduler 의 "5 · LLM 생성" 하나는 남긴다. Grafana 대시보드의 실제 제목을
그대로 인용한 것이라(deploy/monitor/grafana/dashboards/llm-domain.json) 고치면 참조가
가리키는 곳과 어긋난다.
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 32 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 80175aaa-74f8-4f6f-867b-19bb22fadf6e

📥 Commits

Reviewing files that changed from the base of the PR and between 482a4e7 and c0c876f.

📒 Files selected for processing (83)
  • admin-web/src/components/ui/badge.tsx
  • admin-web/src/components/ui/table.tsx
  • admin-web/src/pages/token-usage/usage-table.tsx
  • src/main/kotlin/com/nexters/gamss/admin/controller/AdminDashboardController.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/AdminMemberController.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/ConversationUsageResponse.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/DailyActivityResponse.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/DailyGenerationResponse.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/EmotionCountResponse.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/QualityStatsResponse.kt
  • src/main/kotlin/com/nexters/gamss/admin/controller/dto/UsageStatsResponse.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/ConversationUsage.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/ConversationUsageService.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/DailyActivity.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/DailyGeneration.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/EmotionCount.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/QualityStats.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/QualityStatsService.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/UsageStats.kt
  • src/main/kotlin/com/nexters/gamss/admin/service/UsageStatsService.kt
  • src/main/kotlin/com/nexters/gamss/auth/service/SocialAccountService.kt
  • src/main/kotlin/com/nexters/gamss/card/service/CardPersistenceService.kt
  • src/main/kotlin/com/nexters/gamss/card/service/CardService.kt
  • src/main/kotlin/com/nexters/gamss/card/service/CardStatsService.kt
  • src/main/kotlin/com/nexters/gamss/card/service/DailyAutoCardScheduler.kt
  • src/main/kotlin/com/nexters/gamss/conversation/domain/Conversation.kt
  • src/main/kotlin/com/nexters/gamss/conversation/domain/Message.kt
  • src/main/kotlin/com/nexters/gamss/conversation/repository/ConversationRepository.kt
  • src/main/kotlin/com/nexters/gamss/conversation/repository/ConversationSearchRepository.kt
  • src/main/kotlin/com/nexters/gamss/conversation/repository/UnfinishedConversationProjection.kt
  • src/main/kotlin/com/nexters/gamss/conversation/search/BlindIndexConversationSearcher.kt
  • src/main/kotlin/com/nexters/gamss/conversation/search/ConversationSearchIndexListener.kt
  • src/main/kotlin/com/nexters/gamss/conversation/search/ConversationSearcher.kt
  • src/main/kotlin/com/nexters/gamss/conversation/search/MessageSearchIndexListener.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/ConversationCardGenerationService.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/ConversationSearchService.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/ConversationSenderCount.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/ConversationService.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/ConversationStatsService.kt
  • src/main/kotlin/com/nexters/gamss/conversation/service/UnfinishedConversation.kt
  • src/main/kotlin/com/nexters/gamss/global/crypto/EncryptedStringConverter.kt
  • src/main/kotlin/com/nexters/gamss/global/exception/ErrorCode.kt
  • src/main/kotlin/com/nexters/gamss/global/exception/ErrorKind.kt
  • src/main/kotlin/com/nexters/gamss/global/security/JwtAccessDeniedHandler.kt
  • src/main/kotlin/com/nexters/gamss/global/security/JwtAuthenticationEntryPoint.kt
  • src/main/kotlin/com/nexters/gamss/global/web/GlobalExceptionHandler.kt
  • src/main/kotlin/com/nexters/gamss/global/web/HttpStatusOfErrorKind.kt
  • src/main/kotlin/com/nexters/gamss/member/controller/MemberController.kt
  • src/main/kotlin/com/nexters/gamss/member/controller/dto/TokenUsageResponse.kt
  • src/main/kotlin/com/nexters/gamss/member/service/MemberService.kt
  • src/main/kotlin/com/nexters/gamss/member/service/MemberStatsService.kt
  • src/main/kotlin/com/nexters/gamss/monitoring/metrics/DomainStateMetrics.kt
  • src/main/kotlin/com/nexters/gamss/monitoring/service/GenerationLogStatsService.kt
  • src/main/kotlin/com/nexters/gamss/notification/domain/NotificationLog.kt
  • src/main/kotlin/com/nexters/gamss/notification/domain/NotificationOutcome.kt
  • src/main/kotlin/com/nexters/gamss/notification/domain/NotificationType.kt
  • src/main/kotlin/com/nexters/gamss/notification/push/PushSendResult.kt
  • src/main/kotlin/com/nexters/gamss/notification/repository/NotificationLogRepository.kt
  • src/main/kotlin/com/nexters/gamss/notification/service/CardCreatedNotifier.kt
  • src/main/kotlin/com/nexters/gamss/notification/service/ConversationNotificationOutcomes.kt
  • src/main/kotlin/com/nexters/gamss/notification/service/NotificationLogRecorder.kt
  • src/main/kotlin/com/nexters/gamss/notification/service/NotificationLogStatsService.kt
  • src/main/kotlin/com/nexters/gamss/notification/service/UnfinishedConversationReminder.kt
  • src/main/kotlin/com/nexters/gamss/tokenlimit/service/DailyTokenLimitService.kt
  • src/main/resources/db/migration/V36__notification_log.sql
  • src/test/kotlin/com/nexters/gamss/admin/service/ConversationUsageIntegrationTest.kt
  • src/test/kotlin/com/nexters/gamss/admin/service/DashboardStatsIntegrationTest.kt
  • src/test/kotlin/com/nexters/gamss/architecture/LayerDependencyTest.kt
  • src/test/kotlin/com/nexters/gamss/auth/controller/AuthControllerTest.kt
  • src/test/kotlin/com/nexters/gamss/auth/service/LoginServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/card/service/CardServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/card/service/DailyAutoCardSchedulerTest.kt
  • src/test/kotlin/com/nexters/gamss/conversation/repository/UnfinishedConversationQueryTest.kt
  • src/test/kotlin/com/nexters/gamss/conversation/search/BlindIndexConversationSearcherIntegrationTest.kt
  • src/test/kotlin/com/nexters/gamss/conversation/search/SearchIndexFillIntegrationTest.kt
  • src/test/kotlin/com/nexters/gamss/conversation/service/ConversationSearchServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/global/web/GlobalExceptionHandlerTest.kt
  • src/test/kotlin/com/nexters/gamss/member/service/MemberServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/member/service/MemberStatsServiceTest.kt
  • src/test/kotlin/com/nexters/gamss/notification/service/CardCreatedNotifierTest.kt
  • src/test/kotlin/com/nexters/gamss/notification/service/NotificationLogRecorderTest.kt
  • src/test/kotlin/com/nexters/gamss/notification/service/UnfinishedConversationReminderTest.kt
  • src/test/kotlin/com/nexters/gamss/tokenlimit/service/DailyTokenLimitServiceTest.kt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Test Results

833 tests  +24   833 ✅ +24   2m 44s ⏱️ -8s
111 suites + 4     0 💤 ± 0 
111 files   + 4     0 ❌ ± 0 

Results for commit c0c876f. ± Comparison against base commit 482a4e7.

@github-actions

Copy link
Copy Markdown

Test Coverage

Overall Project 81.05% -1.42% 🍏
Files changed 85.33% 🍏

File Coverage
CardPersistenceService.kt 100% 🍏
CardStatsService.kt 100% 🍏
TokenUsageResponse.kt 100% 🍏
SocialAccountService.kt 100% 🍏
ConversationNotificationOutcomes.kt 100% 🍏
CardCreatedNotifier.kt 100% 🍏
NotificationLogRecorder.kt 100% 🍏
QualityStatsService.kt 100% 🍏
EmotionCount.kt 100% 🍏
UsageStatsService.kt 100% 🍏
MemberController.kt 100% 🍏
ConversationSearchService.kt 100% 🍏
ConversationSenderCount.kt 100% 🍏
ConversationStatsService.kt 100% 🍏
UnfinishedConversation.kt 100% 🍏
EncryptedStringConverter.kt 100% 🍏
PushSendResult.kt 100% 🍏
NotificationOutcome.kt 100% 🍏
NotificationType.kt 100% 🍏
ErrorKind.kt 100% 🍏
ErrorCode.kt 100% 🍏
GenerationLogStatsService.kt 100% 🍏
ConversationSearchIndexListener.kt 100% 🍏
MessageSearchIndexListener.kt 100% 🍏
JwtAuthenticationEntryPoint.kt 100% 🍏
JwtAccessDeniedHandler.kt 100% 🍏
CardService.kt 99.08% 🍏
ConversationService.kt 98.14% -1.86% 🍏
MemberStatsService.kt 98.06% -1.94% 🍏
GlobalExceptionHandler.kt 97.06% 🍏
QualityStats.kt 96.55% -3.45% 🍏
DailyTokenLimitService.kt 96.46% 🍏
DailyAutoCardScheduler.kt 95.55% 🍏
ConversationUsageService.kt 95.08% 🍏
NotificationLogStatsService.kt 94.87% -5.13% 🍏
UsageStats.kt 94.74% -5.26% 🍏
Conversation.kt 93.78% 🍏
UnfinishedConversationReminder.kt 91.18% 🍏
DomainStateMetrics.kt 90.7% 🍏
Message.kt 89.66% 🍏
BlindIndexConversationSearcher.kt 89.23% 🍏
DailyActivity.kt 88.89% -11.11% 🍏
ConversationUsage.kt 85.19% 🍏
HttpStatusOfErrorKind.kt 82.61% -17.39% 🍏
ConversationCardGenerationService.kt 81.74% -18.26% 🍏
NotificationLog.kt 71.74% -28.26% 🍏
MemberService.kt 71.7% 🍏
ConversationRepository.kt 61.71% -3.6% 🍏
DailyGeneration.kt 57.14% -42.86% 🍏
ConversationSearchRepository.kt 57.14% 🍏
AdminDashboardController.kt 33.33% -66.67% 🍏
AdminMemberController.kt 11.84% -11.84% 🍏
DailyActivityResponse.kt 0% -30.77% 🍏
QualityStatsResponse.kt 0% -49.12% 🍏
UsageStatsResponse.kt 0% -57.46% 🍏
DailyGenerationResponse.kt 0% -32.26% 🍏
ConversationUsageResponse.kt 0% -25% 🍏
EmotionCountResponse.kt 0% -24.24% 🍏

@theminjunchoi
theminjunchoi merged commit f195bb4 into prod Aug 28, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant