Skip to content

[GMSS-128] feat: 대화 종료와 감정 카드 생성 - #15

Merged
seunghee17 merged 2 commits into
feature/chat-messagingfrom
feature/chat-card
Aug 9, 2026
Merged

[GMSS-128] feat: 대화 종료와 감정 카드 생성#15
seunghee17 merged 2 commits into
feature/chat-messagingfrom
feature/chat-card

Conversation

@soyeonLee126

@soyeonLee126 soyeonLee126 commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

작업 개요

  • 대화를 끝내고 감정 카드를 만드는 경로입니다. 카드는 이 앱의 최종 산출물이고, 서버가 클라이언트가 보낸
    emotion(캐릭터)과 summary(요약)를 받아 본문(자연스러운 요약)을 만듭니다.

  • 감정은 메시지를 보낼 때마다 증분으로 누적해두고 종료 시점에는 argmax만 합니다.

  • 감정 집계가 발화별 점수의 합이라 증분화해도 배치 분류와 결과가 완전히 같습니다(발화 수로 나누는 건 표시용 확신도라 argmax는 안 바뀝니다).

  • 종료 시점에 발화 N개를 한꺼번에 분류하지 않아 카드 생성 대기가 짧아집니다.

  • 종료와 카드 생성은 한 유즈케이스로 묶지 않았습니다. 종료는 되돌릴 수 없어서, 종료는 성공했고 카드만 실패한
    상태를 화면이 들고 재시도해야 합니다.

base 브랜치

이 PR은 feature/chat-messaging(#14) 위에 쌓여 있습니다. #14가 머지되면 base가 develop으로 전환됩니다.
카드 작업만 보이도록 따로 열었습니다.

작업 유형

  • feat: 새 기능
  • fix: 버그 수정
  • refactor: 리팩토링 (동작 변경 없음)
  • build: 빌드/의존성 설정
  • chore: 기타 (문서, 설정 등)
  • test: 테스트 추가/수정

변경 사항

감정 누적을 ConversationSession 에 편입

  • ConversationSession 이 이미 "서버에 확정된 USER 발화만 파생 상태에 미러링한다"는 순서를 강제하고
    있어서, 감정 누적기도 같은 자리에 넣었습니다. 화면은 세션 하나만 의존한 채로 남습니다.
  • ConversationEmotionAccumulator: 압축본과 같은 append(싼 적재) / classifyPending(모델 실행)
    으로 나눴습니다. 전송 응답이 온디바이스 추론을 기다리지 않고 화면에 붙습니다.
  • 방에 재진입할 때는 발화를 큐에 넣기만 합니다. 분류는 첫 전송이나 카드 생성 시점에 몰아서 돕니다.
  • 분류에 실패한 발화는 그 자리에서 멈추고 다음에 다시 시도합니다. 같은 자리에서 두 번 실패하면
    건너뜁니다.
  • 상태 잠금과 분류 잠금을 분리해, 분류가 도는 동안에도 새 발화를 받습니다.

종료 흐름 상태를 EndFlow 로 통합

  • isEnded/isFinishing/showEndConfirm/card/endedButCardFailed 조합 32가지 중 6가지만 합법이라, 화면과 ViewModel 이 유효 조합을 매번 다시 계산해야 했습니다.
  • sealed interface 한 축으로 모아 불가능한 상태를 타입에서 없앴습니다.
NotStarted -> Confirming -> Ending -> CreatingCard -> CardReady(card)
                                                   -> CardFailedRetryable
                                                   -> CardFailedFinal
  • 화면 분기가 exhaustive when 이라 단계를 추가하면 컴파일 에러로 알려줍니다.
  • 재시도해도 결과가 같은 실패는 CardNotRetryableException(AlreadyExists / NoSummary / NoEmotion)으로 묶어 CardFailedFinal 로 보냅니다.

종료·카드 API

  • POST /api/conversations/{id}/end, POST /api/cards 연동
  • 카드 API 의 emotion 은 모델 6감정이 아니라 캐릭터 6종입니다(JOY/ANGER/ANXIETY/GRUMPY/WARM/QUIRKY).
    도메인 PRICKLY 가 서버 GRUMPY 에 대응하고, 서버 문자열 매핑은 EmotionTypeMapping 한 곳에 모았습니다
  • 종료 응답은 ApiResponse<Unit> 으로 받습니다.
  • ApiErrorCodes: 서버 error.code 로 판별합니다. CONVERSATION_ALREADY_ENDED 는 멱등 성공으로
    접고(응답이 유실된 뒤 재시도해도 복구됩니다), CARD_ALREADY_EXISTS 는 도메인 예외로 구분합니다.

온디바이스 실패 격리를 공용 헬퍼로

요약 저장소가 들고 있던 failSafedomain/common 으로 옮겼습니다.

관련 이슈

  • 없음

관련 작업 (Notion)

스크린샷 / 동작 화면

체크리스트

테스트

  • :app:assembleDebug, 단위 테스트 90개, detekt 전부 통과입니다.
  • 상태 기계 테스트(ChatRoomEndFlowTest) 9개를 새로 넣었습니다.
  • 누적기의 잠금 분리도 테스트로 고정했습니다. 잠금을 하나로 합치면 분류가_도는_동안에도_새_발화를_받는다
    가 타임아웃으로 깨집니다.

요약 저장소가 들고 있던 failSafe 를 domain/common 으로 옮긴다. "온디바이스 모델 실패는
삼키되 취소는 삼키지 않는다" 는 하나의 정책이라, 복사본에서 ensureActive 를 빠뜨리면
취소가 성공처럼 보여 조용히 틀린다.
대화를 끝내고 그 대화의 감정 카드를 만든다. 종료와 카드 생성은 묶지 않는다. 종료는
되돌릴 수 없어서, 종료는 됐고 카드만 실패한 상태를 화면이 들고 있어야 한다.

감정 누적기와 종료·카드 생성을 ConversationSession 에 넣는다. 누적기도 압축본과 같이
서버에 확정된 USER 발화만 미러링해야 해서, 순서 규칙을 한 곳에 두면 화면은 세션 하나만
의존한 채로 남는다. 누적기는 압축본과 같은 append/compact 로 나눠, 전송 응답이 온디바이스
추론을 기다리지 않고 화면에 붙는다.

종료 흐름 상태는 sealed interface EndFlow 한 축으로 둔다. 불리언으로 나누면 "종료 전인데
카드가 있음" 같은 조합이 타입상 표현되고 화면이 매번 유효 조합을 다시 계산해야 한다.
재시도해도 결과가 같은 실패는 CardNotRetryableException 으로 묶어 재시도 경로를 닫는다.
영구히 같은 오류를 반복시키지 않기 위해서다.

분류가 실패한 발화는 두 번까지 다시 시도하고 그 뒤엔 건너뛴다. 무한히 붙들면 뒤 발화가
영영 누적되지 않는다. 분류 실패는 대화를 막지 않도록 격리한다.

종료 응답은 ApiResponse<Unit> 으로 받는다. 본문을 읽지 않으므로 서버 스키마가 바뀌어도
종료가 실패로 뒤집히지 않는다.
@soyeonLee126 soyeonLee126 changed the title feat: 대화 종료와 감정 카드 생성 [GMSS-128] feat: 대화 종료와 감정 카드 생성 Aug 6, 2026
@soyeonLee126
soyeonLee126 marked this pull request as ready for review August 6, 2026 09:55

@seunghee17 seunghee17 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

문제가 없어보여 merge 합니다! 고생하셨습니다!

@seunghee17
seunghee17 merged commit 9fd75cd into feature/chat-messaging Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants