Skip to content

[HSC-396] 실시간 이탈 위험도 커서 조회 추가#249

Merged
tkv00 merged 3 commits into
devfrom
feat/HSC-396
Mar 19, 2026
Merged

[HSC-396] 실시간 이탈 위험도 커서 조회 추가#249
tkv00 merged 3 commits into
devfrom
feat/HSC-396

Conversation

@tkv00
Copy link
Copy Markdown
Contributor

@tkv00 tkv00 commented Mar 19, 2026

📝작업 내용

  • 관리자 대시보드용 실시간 이탈 위험도 조회 API 추가
  • 초기 진입용 latest API와 3초 폴링용 changes API를 커서 기반 구현
  • churn_score_snapshot에 변경 커서용 revision_idupdated_at을 추가하고, churn snapshot 저장 시점마다 함께 갱신되도록 변경
  • 목록 응답은 첫 번째 risk_reasons.summaryreason으로 내려주고, 회원 이름은 복호화 후 마스킹해서 반환 구현

👀변경 사항

변경 요약

구분 변경 내용 비고
신규 API GET /api/v1/admin/churn/latest 대시보드 최초 진입용
신규 API GET /api/v1/admin/churn/changes 폴링 변경분 조회용
커서 컬럼 churn_score_snapshot.revision_id 추가 afterId로 사용
시각 컬럼 churn_score_snapshot.updated_at 추가 응답 timeStamp로 사용
저장 로직 snapshot upsert 시 revision_id, updated_at 갱신 변경 감지 가능
응답 조립 risk_reasons[0].summary -> reason 목록 표시용
레벨 파라미터 HIGH,MEDIUM 지원 MID 미사용

API 스펙

API 설명 주요 파라미터
/api/v1/admin/churn/latest 최신 이탈 위험도 목록 조회 limit, level
/api/v1/admin/churn/changes 마지막 커서 이후 변경분 조회 afterId, limit, level

응답 아이템 매핑

응답 필드 소스
churnId churn_score_snapshot.revision_id
memberId member.member_id
reason risk_reasons 첫 번째 summary
churnLevel churn_score_snapshot.risk_level
memberName 복호화 후 마스킹된 회원명
timeStamp churn_score_snapshot.updated_at

주요 변경 파일

파일 역할
src/main/java/site/holliverse/admin/web/controller/ChurnRealTimeController.java latest/changes API 진입점
src/main/java/site/holliverse/admin/web/dto/churn/ChurnRealTimeRequestDto.java 실시간 조회 요청 파라미터 정규화
src/main/java/site/holliverse/admin/web/dto/churn/ChurnRealTimeResponseDto.java 실시간 조회 응답 DTO
src/main/java/site/holliverse/admin/application/usecase/RetrieveChurnRealtimeUseCase.java latest/changes 조회 오케스트레이션
src/main/java/site/holliverse/admin/query/dao/ChurnRealtimeDao.java 커서 기반 churn snapshot 조회
src/main/java/site/holliverse/admin/query/dao/ChurnRealtimeRawData.java DAO 조회 중간 객체
src/main/java/site/holliverse/admin/web/assembler/ChurnRealtimeAssembler.java 응답 조립, 이름 마스킹, reason 추출
src/main/java/site/holliverse/admin/application/usecase/ChurnSnapshotStoreService.java snapshot 저장 시 revision/update 시각 반영
src/main/resources/db/migration/V34__add_churn_revision_cursor.sql revision_id, updated_at 추가 migration

변경 로직

flowchart LR
    A["상담 / 로그 / 배치 feature 갱신"] --> B["ChurnSnapshotStoreService"]
    B --> C["churn_score_snapshot upsert"]
    C --> D["revision_id 재발급"]
    C --> E["updated_at 갱신"]

    F["GET /churn/latest"] --> G["revision_id desc 조회"]
    H["GET /churn/changes?afterId=N"] --> I["revision_id > N 조회"]

    G --> J["ChurnRealtimeAssembler"]
    I --> J
    J --> K["items / afterId / hasMore 응답"]
Loading

저장 구조 변경

flowchart TD
    A["기존 feature score 계산"] --> B["총 churn score 계산"]
    B --> C["churn_score_snapshot 저장"]
    C --> D["revision_id 증가"]
    C --> E["updated_at = now()"]

    D --> F["폴링 커서 사용"]
    E --> G["목록 시각 표시"]
Loading

사이드 이펙트

항목 내용
커서 의미 revision_id는 변경 히스토리 테이블이 아니라 현재 snapshot row의 최신 변경 커서입니다.
중간 상태 보존 같은 회원이 짧은 시간 내 여러 번 갱신되면 폴링 시 최신 상태만 보일 수 있습니다.
초기 배포 기존 row는 migration 시 기본 revision_id, updated_at이 채워지고 이후 갱신부터 실시간 커서 의미가 명확해집니다.
날짜 기준 조회 대상은 base_date = today 조건을 유지합니다.

검증

항목 결과
./gradlew compileJava -x flywayMigrate -x generateJooq 성공
./gradlew test --tests "*ArchitectureRulesTest" -x flywayMigrate -x generateJooq 성공
도커 postgres 시드 적재 MEDIUM 500건 / HIGH 500건 적재 완료
최신 커서 확인 afterId = 10001000 확인

🎫 Jira Ticket

  • Jira Ticket: HSC-396

#️⃣관련 이슈


@github-actions github-actions Bot added Admin Team ✨ feat 새로운 기능 추가, 기존 기능을 요구 사항에 맞추어 수정 🔥 priority: P0 즉시 처리 필요(서비스/데모 블로커) 🗂️ area: BE 백엔드 영역 labels Mar 19, 2026
@github-actions github-actions Bot changed the title 실시간 이탈 위험도 커서 조회 추가 [HSC-396] 실시간 이탈 위험도 커서 조회 추가 Mar 19, 2026
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 관리자 대시보드에서 실시간 이탈 위험도를 효율적으로 모니터링할 수 있도록 새로운 API 엔드포인트를 도입합니다. 커서 기반의 데이터 조회 방식을 통해 초기 데이터 로딩과 이후 변경분 폴링을 최적화하고, 이탈 스냅샷 데이터에 변경 이력을 추적할 수 있는 필드를 추가하여 시스템의 실시간성을 강화했습니다. 이를 통해 관리자는 최신 이탈 위험 정보를 신속하게 파악하고 대응할 수 있습니다.

Highlights

  • 신규 API 추가: 관리자 대시보드용 실시간 이탈 위험도 조회 API인 /api/v1/admin/churn/latest (초기 진입용)와 /api/v1/admin/churn/changes (폴링용)가 추가되었습니다.
  • 커서 기반 구현: 초기 진입 및 폴링 API 모두 커서 기반으로 구현되어 효율적인 데이터 변경분 조회가 가능합니다.
  • 데이터베이스 스키마 변경: churn_score_snapshot 테이블에 revision_idupdated_at 컬럼이 추가되었으며, 이탈 스냅샷 저장 시 함께 갱신됩니다.
  • 응답 데이터 처리: 응답 시 risk_reasons의 첫 번째 summaryreason으로 사용되며, 회원 이름은 복호화 후 마스킹 처리되어 반환됩니다.
  • 지원 레벨: 이탈 위험도 조회 시 HIGHMEDIUM 레벨 필터링이 지원됩니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

관리자 대시보드용 실시간 이탈 위험도 조회 API를 추가하는 변경 사항입니다. 커서 기반 페이지네이션을 도입하여 latestchanges API를 구현하였고, 이를 위해 DB 스키마와 데이터 저장 로직을 수정했습니다. 전반적인 아키텍처와 구현은 훌륭하지만, 데이터 조회 로직의 정렬 순서에 버그가 있고, 스타일 가이드 위반 및 코드 중복 문제가 발견되어 수정이 필요합니다.

Comment thread src/main/java/site/holliverse/admin/query/dao/ChurnRealtimeDao.java
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 19, 2026

🧪 Test Coverage Report (JaCoCo)

overall__line overall__branch changed__line changed__branch

기준(soft, workflow는 실패 안 함): Overall line 70% / branch 50%, Changed line 80% / branch 60% · Generated: 2026-03-19 18:36 UTC

Scope Line Branch Line Graph Branch Graph Verdict
Overall 42.6% 30.3% █████████░░░░░░░░░░░ ██████░░░░░░░░░░░░░░ ⚠️⚠️
Changed 4.1% 0.0% █░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░ ⚠️⚠️

Package line spark (sample): ▃▂▁▂▂▄▄·▇█▆▆▆▁▁▆█▇▄▁▁▁██▁▁▃·▆▁
Package branch spark (sample): ▃▁·▁▁·▁·▇·▅▆▅▁▁▅▇▇▃▁·▁·█▁▁▁·▅▁

📦 Package coverage (worst 10)

Rank Package Line Branch Lines Line Graph Branch Graph
1 site.holliverse.customer.application.usecase.log 0.0% 0.0% 63 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
2 site.holliverse.customer.coupon.application 0.0% 0.0% 61 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
3 site.holliverse.infra.kafka.consumer 0.0% 0.0% 51 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
4 site.holliverse.customer.integration.external 0.0% 0.0% 22 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
5 site.holliverse.customer.integration.fastapi 0.0% 0.0% 19 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
6 site.holliverse.customer.application.usecase.counsel 0.0% 0.0% 14 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
7 site.holliverse.customer.coupon.web 0.0% 0.0% 12 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
8 site.holliverse.shared.config.runtime 0.0% N/A 11 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
9 site.holliverse.customer.web.util 0.0% 0.0% 8 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
10 site.holliverse.admin.domain.model.churn.feature 0.0% N/A 8 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░

🧨 Lowest coverage classes (worst 10)

Rank Class Line Branch Lines Line Graph Branch Graph
1 site.holliverse.infra.kafka.consumer.RecommendationKafkaConsumer 0.0% 0.0% 51 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
2 site.holliverse.customer.application.usecase.log.UserLogService 0.0% 0.0% 46 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
3 site.holliverse.admin.application.usecase.CalculateLogChurnScoreService 0.0% 0.0% 38 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
4 site.holliverse.admin.application.usecase.CalculateChurnScoreService 0.0% 0.0% 37 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
5 site.holliverse.customer.coupon.application.UseMemberCouponUseCase 0.0% 0.0% 34 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
6 site.holliverse.admin.application.usecase.ChurnRiskReason$ReasonCode 0.0% 0.0% 31 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
7 site.holliverse.customer.coupon.application.GetMemberCouponsUseCase 0.0% 0.0% 27 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
8 site.holliverse.admin.application.usecase.MemberDissatisfactionFeatureSnapshotService 0.0% 0.0% 27 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
9 site.holliverse.admin.web.controller.InternalAnalysisWebhookController 0.0% 0.0% 27 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
10 site.holliverse.admin.application.usecase.RetrieveChurnRealtimeUseCase 0.0% 0.0% 24 ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
🧩 Changed files coverage breakdown (8 files)
File Line Branch Lines Verdict Line Graph Branch Graph
src/main/java/site/holliverse/admin/application/usecase/RetrieveChurnRealtimeUseCase.java 0.0% 0.0% 24 ⚠️⚠️ ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
src/main/java/site/holliverse/admin/web/controller/ChurnRealTimeController.java 0.0% N/A 6 ⚠️ ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
src/main/java/site/holliverse/admin/application/usecase/ChurnSnapshotStoreService.java 5.4% 0.0% 93 ⚠️⚠️ █░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
src/main/java/site/holliverse/admin/query/dao/ChurnRealtimeDao.java N/A N/A 0 ✅✅ ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
src/main/java/site/holliverse/admin/query/dao/ChurnRealtimeRawData.java N/A N/A 0 ✅✅ ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
src/main/java/site/holliverse/admin/web/assembler/ChurnRealtimeAssembler.java N/A N/A 0 ✅✅ ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
src/main/java/site/holliverse/admin/web/dto/churn/ChurnRealTimeRequestDto.java N/A N/A 0 ✅✅ ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░
src/main/java/site/holliverse/admin/web/dto/churn/ChurnRealTimeResponseDto.java N/A N/A 0 ✅✅ ░░░░░░░░░░░░░░░░░░░░ ░░░░░░░░░░░░░░░░░░░░

🔎 HTML 리포트: Actions → Artifacts → jacoco-html · XML: jacoco-xml

Copy link
Copy Markdown
Contributor

@bon0512 bon0512 left a comment

Choose a reason for hiding this comment

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

고생하셨습니다.

@tkv00 tkv00 merged commit b58e21d into dev Mar 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Admin Team 🗂️ area: BE 백엔드 영역 ✨ feat 새로운 기능 추가, 기존 기능을 요구 사항에 맞추어 수정 🔥 priority: P0 즉시 처리 필요(서비스/데모 블로커)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[HSC-396] 실시간 이탈률 API 구현

2 participants