Skip to content

[FEAT] 라이브 공유 기록 · 어드민 통계 · 종료 디스코드 알림 - #277

Merged
coli-geonwoo merged 8 commits into
developfrom
chore/#276-logging
Oct 6, 2026
Merged

coli-geonwoo merged 8 commits into
developfrom
chore/#276-logging

Conversation

@coli-geonwoo

@coli-geonwoo coli-geonwoo commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

🚩 연관 이슈

closed #276

배경

라이브 공유(사회자 → 청중 STOMP 동기화)가 하루에 얼마나 쓰이는지, 한 번에 몇 분 정도 이어지는지 알 수 없었다.
공유 한 번을 DB 한 행으로 기록하고, 어드민 페이지에서 일별 통계를 보고, 공유가 끝나면 디스코드로 알림을 받는다.

작업

1. 공유 기록 (sharing_log, V17)

  • 컬럼: table_id, member_id, started_at, ended_at, audience_count, status(SHARING / FINISHED / ABANDONED)
  • 사회자가 사회자 채널 구독에 성공하면 행이 생기고, 청중이 구독할 때마다 audience_count를 원자적으로 +1 한다(재접속도 함께 셈)
  • 사회자가 FINISHED를 보내면 행을 FINISHED로 닫고 종료 이벤트를 발행한다
  • 공유 기록에 실패해도 공유 중계는 계속한다(WARN 로그만 남김)

2. FINISHED 없이 사회자 연결이 끊긴 경우

  • 끊긴 뒤 1분 안에 다시 구독하면 같은 행을 이어서 쓴다(재연결, 다른 기기로 이전)
  • 1분 안에 돌아오지 않으면 1분 주기 스케줄러가 정리한다
    • 마지막 타임박스까지 진행했으면 FINISHED, 아니면 ABANDONED(종료 시각은 끊긴 시각)
    • 이 경우 디스코드 알림은 보내지 않는다
  • 마지막 순서 판정: FE의 sequence는 0부터 시작하고, NEXT/BEFORE는 이동하기 전 index를 보내므로 서버에서 이동한 뒤 순서로 바꿔 판단한다
  • 12시간이 넘은 SHARING 행(서버 재시작 등으로 추적이 끊긴 경우)은 ABANDONED로 정리한다
  • 이를 위해 ChairmanSessionRegistry.release가 해제한 룸을 Optional<Long>으로 돌려준다

3. 공유 종료 디스코드 알림

  • 명시적 FINISHED가 커밋된 뒤 @Async + @TransactionalEventListener(AFTER_COMMIT)로 보낸다
  • 기존 봇과 JDA 인스턴스를 같이 쓰도록 JDA를 빈으로 분리하고, 새 설정 discord.sharingChannelId 채널로 보낸다
  • 메시지에는 누적 공유 횟수(공유 기록 id), 사회자, 테이블, 공유 시간, 진행 시각, 참여 청중 수가 들어간다
  • local/test 프로필은 콘솔 로그로 대신한다
  • 기본 Executor를 그대로 쓴다. 전용 Executor 빈을 만들면 Boot 3.4의 기본 applicationTaskExecutor 구성이 꺼지기 때문이다

4. 어드민 통계

  • GET /api/admin/sharing/stats?from=&to=: X-Admin-Password 헤더 검증(고정 시간 비교), 최대 366일
  • FINISHED 공유만 시작일 기준으로 모아 일별 횟수와 평균 공유 시간(분)을 계산하고, 기록이 없는 날은 0으로 채운다
  • /admin.html: 비밀번호 입력 → 기간 선택 → Chart.js 막대그래프 2개(일별 횟수, 일별 평균 시간)와 기간 요약

배포 전 설정 (dev / prod secret)

secret:
  discord:
    sharingChannelId: <공유 알림 채널 ID>
  admin:
    password: <어드민 비밀번호>

값이 비어 있으면 서버가 뜨지 않는다.

테스트

  • 단위/통합 테스트 추가: SharingLogServiceTest, SharingLogEntityTest, SharingStatsServiceTest, AdminSharingControllerTest, AdminAuthorizerTest, AdminPropertiesTest, SharingFinishedListenerTest, SharingFinishedMessageTest, DiscordSharingNotifierTest, SharingServiceTest / ChairmanSessionRegistryTest 보강
  • 전체 ./gradlew test 508개 통과, Flyway V17 검증(DatabaseSchemaManagerTest) 포함
  • 로컬 E2E: STOMP 스크립트로 공유 시작 → 청중 3명 → PLAY/NEXT/NEXT → FINISHED를 진행하고, 실제 sharing-dev 채널에 알림이 오는 것까지 확인
  • 커밋마다 따로 컴파일되는지 확인

🗣️ 리뷰 요구사항 (선택)

  • 청중 수는 구독 횟수 기준이라 재접속도 함께 센다(의도한 러프 집계)
  • 디스코드 메시지의 누적 횟수는 공유 기록 id라 ABANDONED 공유도 포함된다

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 새 기능
    • 라이브 공유 기록을 수집해 종료 횟수, 평균 공유 시간, 청중 수 등을 확인할 수 있습니다.
    • 관리자 페이지에서 비밀번호 인증 후 날짜별 공유 통계를 조회하고 차트로 확인할 수 있습니다.
    • 공유가 종료되면 Discord 공유 채널로 알림을 보냅니다.
  • 개선 사항
    • 연결이 끊긴 공유 기록을 정리하고, 재연결 시 유예 시간 내 기록을 이어서 추적합니다.
    • 통계 조회 기간과 관리자 비밀번호를 검증합니다.

coli-geonwoo and others added 8 commits October 7, 2026 01:19
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coli-geonwoo coli-geonwoo added the chore 기타 label Oct 6, 2026
@coli-geonwoo coli-geonwoo linked an issue Oct 6, 2026 that may be closed by this pull request
@coli-geonwoo coli-geonwoo self-assigned this Oct 6, 2026
@coderabbitai

coderabbitai Bot commented Oct 6, 2026

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: Repository: debate-timer/debate-timer-be/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: bef22a09-c10a-4fec-b5c5-719e149e16f0
📥 Commits

Reviewing files that changed from the base of the PR and between 04df2df and 78b6274.

📒 Files selected for processing (45)
  • src/main/java/com/debatetimer/client/notifier/ConsoleSharingNotifier.java
  • src/main/java/com/debatetimer/client/notifier/DiscordNotifier.java
  • src/main/java/com/debatetimer/client/notifier/DiscordProperties.java
  • src/main/java/com/debatetimer/client/notifier/DiscordSharingNotifier.java
  • src/main/java/com/debatetimer/client/notifier/SharingFinishedMessage.java
  • src/main/java/com/debatetimer/client/notifier/SharingNotifier.java
  • src/main/java/com/debatetimer/config/AsyncConfig.java
  • src/main/java/com/debatetimer/config/AuthenticationConfig.java
  • src/main/java/com/debatetimer/config/NotifierConfig.java
  • src/main/java/com/debatetimer/controller/admin/AdminAuthorizer.java
  • src/main/java/com/debatetimer/controller/admin/AdminProperties.java
  • src/main/java/com/debatetimer/controller/admin/AdminSharingController.java
  • src/main/java/com/debatetimer/domain/sharing/SharingLogStatus.java
  • src/main/java/com/debatetimer/domainrepository/customize/CustomizeTableDomainRepository.java
  • src/main/java/com/debatetimer/dto/admin/SharingDailyStatResponse.java
  • src/main/java/com/debatetimer/dto/admin/SharingStatsResponse.java
  • src/main/java/com/debatetimer/entity/sharing/SharingLogEntity.java
  • src/main/java/com/debatetimer/event/sharing/SharingFinishedEvent.java
  • src/main/java/com/debatetimer/event/sharing/SharingFinishedListener.java
  • src/main/java/com/debatetimer/exception/errorcode/ClientErrorCode.java
  • src/main/java/com/debatetimer/exception/errorcode/InitializationErrorCode.java
  • src/main/java/com/debatetimer/repository/customize/CustomizeTimeBoxRepository.java
  • src/main/java/com/debatetimer/repository/sharing/SharingLogRepository.java
  • src/main/java/com/debatetimer/scheduler/SharingRoomCleanupScheduler.java
  • src/main/java/com/debatetimer/service/admin/SharingStatsService.java
  • src/main/java/com/debatetimer/service/sharing/ChairmanSessionRegistry.java
  • src/main/java/com/debatetimer/service/sharing/SharingLogService.java
  • src/main/java/com/debatetimer/service/sharing/SharingService.java
  • src/main/resources/application-dev.yml
  • src/main/resources/application-prod.yml
  • src/main/resources/db/migration/V17__create_sharing_log_table.sql
  • src/main/resources/static/admin.html
  • src/test/java/com/debatetimer/client/DiscordPropertiesTest.java
  • src/test/java/com/debatetimer/client/notifier/DiscordSharingNotifierTest.java
  • src/test/java/com/debatetimer/client/notifier/SharingFinishedMessageTest.java
  • src/test/java/com/debatetimer/controller/admin/AdminAuthorizerTest.java
  • src/test/java/com/debatetimer/controller/admin/AdminPropertiesTest.java
  • src/test/java/com/debatetimer/controller/admin/AdminSharingControllerTest.java
  • src/test/java/com/debatetimer/entity/sharing/SharingLogEntityTest.java
  • src/test/java/com/debatetimer/event/sharing/SharingFinishedListenerTest.java
  • src/test/java/com/debatetimer/service/admin/SharingStatsServiceTest.java
  • src/test/java/com/debatetimer/service/sharing/ChairmanSessionRegistryTest.java
  • src/test/java/com/debatetimer/service/sharing/SharingLogServiceTest.java
  • src/test/java/com/debatetimer/service/sharing/SharingServiceTest.java
  • src/test/resources/application.yml
 ________________________________________________________________________________________________________________________________________
< Use assertions to prevent the impossible. Assertions validate your assumptions. Use them to protect your code from an uncertain world. >
 ----------------------------------------------------------------------------------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

Test Results

188 files  188 suites   57s ⏱️
492 tests 492 ✅ 0 💤 0 ❌
508 runs  508 ✅ 0 💤 0 ❌

Results for commit 78b6274.

@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

📝 Test Coverage Report

Overall Project 92.67% -0.7% 🍏
Files changed 95.55% 🍏

File Coverage
SharingFinishedListener.java 100% 🍏
SharingFinishedEvent.java 100% 🍏
AuthenticationConfig.java 100% 🍏
AsyncConfig.java 100% 🍏
DiscordProperties.java 100% 🍏
SharingFinishedMessage.java 100% 🍏
DiscordSharingNotifier.java 100% 🍏
SharingLogEntity.java 100% 🍏
SharingService.java 100% 🍏
AdminSharingController.java 100% 🍏
AdminProperties.java 100% 🍏
AdminAuthorizer.java 100% 🍏
SharingLogStatus.java 100% 🍏
SharingStatsService.java 100% 🍏
CustomizeTableDomainRepository.java 100% 🍏
ClientErrorCode.java 100% 🍏
InitializationErrorCode.java 100% 🍏
SharingRoomCleanupScheduler.java 100% 🍏
SharingLogService.java 99.15% -0.85% 🍏
ChairmanSessionRegistry.java 98.82% -0.59% 🍏
ConsoleSharingNotifier.java 53.85% -46.15% ❌
NotifierConfig.java 27.5% -72.5% ❌
DiscordNotifier.java 0% -10.42% ❌

@coli-geonwoo
coli-geonwoo merged commit 5de1887 into develop Oct 6, 2026
4 of 5 checks passed
@coli-geonwoo
coli-geonwoo deleted the chore/#276-logging branch October 6, 2026 17:57
return LocalDateTime.ofInstant(instant, clock.getZone());
}

private record ActiveSharing(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

이너 레코드 쓰지 않는 것 AGents.md에 넣어두기

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore 기타

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CHORE] 공유기능 사용량 + 평균 토론 시간 로깅

1 participant