Skip to content

[FEAT] 라이브 공유 사회자 단일 세션 및 사회자 부재 처리 - #497

Merged
coli-geonwoo merged 6 commits into
developfrom
feat/#496-chairman-single-session
Sep 24, 2026
Merged

coli-geonwoo merged 6 commits into
developfrom
feat/#496-chairman-single-session

Conversation

@coli-geonwoo

@coli-geonwoo coli-geonwoo commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

🚩 연관 이슈

closed #496

📝 작업 내용

사회자 단일 세션 (다중 탭 / 재연결 경합)

  • 공유를 시작할 때마다 사회자 세션 식별자를 만들어 구독·발행 헤더(X-Chairman-Session)에 첨부 (자동 재연결 시에는 유지)
  • REPLACED 알림을 받으면 밀려난 상태로 전환하고 자동 재연결 없이 연결 해제
  • 밀려난 탭: 공유 모달로 "다른 곳에서 공유 중" 안내, "이 화면에서 다시 공유하기"로 되찾기 가능
  • 현재 공유 중인 사회자 탭은 공유 버튼 중앙 하단에 펄스 점 표시

사회자 부재 처리 (청중)

  • 서버의 CHAIRMAN_ABSENT 알림 또는 연결 후 15초 동안 사회자 메시지가 없으면 absent로 판정해 기존 부재 안내 표시
  • CHAIRMAN_ABSENT는 사회자 메시지 수신 기록·version 기준과 분리

사회자 토큰 선제 갱신

  • 공유 중이면 토큰 만료 1분 전에 새 토큰을 받음
  • 갱신을 놓쳐(절전 등) 만료된 토큰으로 발행하면 즉시 새 토큰 요청

기타

  • useSocket.subscribe에 헤더 지원 (함수로 넘기면 재구독 시 최신 값 적용)
  • SocketManager.disconnect()가 리스너를 지우던 문제 수정 (같은 화면에서 다시 연결하면 로딩이 끝나지 않던 버그)

테스트

  • 소켓 훅, 공유 상태, 모달·버튼 테스트 추가, 전체 466개 통과

🏞️ 스크린샷 (선택)

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

  • ⚠️ BE가 헤더 없는 발행을 거부하므로 BE(debate-timer-be#267)와 동시 배포가 필요합니다
  • 청중 화면 남은 시간 배경색 적용은 시간 가시성 문제로 되돌렸습니다 (커밋 이력에 남아 있음)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 새 기능
    • 라이브 공유 버튼에 현재 공유 중임을 나타내는 표시를 추가했습니다.
    • 다른 탭이나 기기에서 공유가 시작되면 중단 상태와 안내를 표시하고, 현재 화면에서 공유를 다시 시작할 수 있습니다.
    • 청중 화면에서 사회자의 부재 상태를 더 빠르게 확인할 수 있습니다.
  • 개선 사항
    • 공유 연결이 끊기지 않도록 토큰을 만료 전에 갱신합니다.

coli-geonwoo and others added 6 commits September 25, 2026 01:17
- 공유 시작마다 사회자 세션 식별자를 만들어 구독·발행 헤더(X-Chairman-Session)에 첨부
- REPLACED 알림을 받으면 밀려난 상태로 전환하고 자동 재연결 없이 연결 해제
- 청중 소켓에서 CHAIRMAN_ABSENT를 사회자 메시지와 분리해 chairmanAbsentAt으로 노출
- 구독 헤더 지원(재구독 시 최신 값 적용), 수동 연결 해제 후에도 리스너 유지

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 다른 탭/기기에서 공유를 시작하면 공유 모달로 안내하고 이 화면에서 다시 공유할 수 있게 함
- 밀려난 상태에서는 모달이 열려 있어도 자동으로 다시 연결하지 않음
- 현재 공유 중인 사회자 탭의 공유 버튼에 펄스 점 표시

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 서버의 CHAIRMAN_ABSENT 알림 또는 연결 후 15초 동안 사회자 메시지가 없으면 absent로 판정
- 타이머 배경색 계산을 공용 유틸로 분리하고 청중 화면에도 같은 기준 적용
  (30초 이하 노란색, 10초 이하 붉은색, 0초 미만 회색)

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>
- 공유 중이면 사회자 토큰 만료 1분 전에 새 토큰을 받아 발행이 끊기지 않게 함
- 절전 등으로 갱신을 놓쳐 만료된 토큰으로 발행하면 즉시 새 토큰을 요청

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coli-geonwoo coli-geonwoo self-assigned this Sep 24, 2026
@coderabbitai

coderabbitai Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 80abdddb-c329-4c98-94e1-4c70ad927ffe

📥 Commits

Reviewing files that changed from the base of the PR and between 64f7d4e and db17d5f.

📒 Files selected for processing (26)
  • public/locales/en/translation.json
  • public/locales/ko/translation.json
  • src/apis/sockets/SocketManager.test.ts
  • src/apis/sockets/SocketManager.ts
  • src/apis/sockets/type.ts
  • src/apis/sockets/util.test.ts
  • src/apis/sockets/util.ts
  • src/hooks/sockets/useAudienceSocket.test.ts
  • src/hooks/sockets/useAudienceSocket.ts
  • src/hooks/sockets/useChairmanSocket.test.ts
  • src/hooks/sockets/useChairmanSocket.ts
  • src/hooks/sockets/useSocket.test.ts
  • src/hooks/sockets/useSocket.ts
  • src/page/AudienceSharePage/hooks/useAudienceShareState.test.ts
  • src/page/AudienceSharePage/hooks/useAudienceShareState.ts
  • src/page/TimerPage/TimerPage.tsx
  • src/page/TimerPage/components/LiveShareButton.stories.tsx
  • src/page/TimerPage/components/LiveShareButton.test.tsx
  • src/page/TimerPage/components/LiveShareButton.tsx
  • src/page/TimerPage/components/LiveShareModal.stories.tsx
  • src/page/TimerPage/components/LiveShareModal.test.tsx
  • src/page/TimerPage/components/LiveShareModal.tsx
  • src/page/TimerPage/hooks/useLiveShare.test.ts
  • src/page/TimerPage/hooks/useLiveShare.ts
  • src/util/jwt.test.ts
  • src/util/jwt.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

소켓 구독 및 발행에 사회자 세션 ID를 전달하고 세션 교체를 처리합니다. 청중 화면은 서버 알림과 연결 후 무응답으로 사회자 부재를 판단합니다. 라이브 공유 버튼과 모달에 공유 상태 및 재시작 UI를 추가하고, 사회자 토큰 갱신을 처리합니다.

Changes

라이브 공유 세션

Layer / File(s) Summary
소켓 계약과 구독 헤더
src/apis/sockets/type.ts, src/apis/sockets/util.ts, src/apis/sockets/util.test.ts, src/apis/sockets/SocketManager.ts, src/apis/sockets/SocketManager.test.ts, src/hooks/sockets/useSocket.ts, src/hooks/sockets/useSocket.test.ts
서버 이벤트와 사회자 알림 타입 및 검증을 추가했습니다. 소켓 구독은 선택적 헤더를 전달하고, 함수형 헤더는 최초 구독과 재연결 때 평가합니다. 연결 해제 후에도 연결 리스너를 유지합니다.
사회자 세션 교체 처리
src/hooks/sockets/useChairmanSocket.ts, src/hooks/sockets/useChairmanSocket.test.ts
구독 및 발행에 사회자 세션 ID를 전달합니다. 다른 세션의 REPLACED 알림을 받으면 연결을 끊고 isReplaced를 설정합니다. SYNC_REQUEST 알림은 동기화 콜백으로 전달합니다.
청중의 사회자 부재 상태
src/hooks/sockets/useAudienceSocket.ts, src/hooks/sockets/useAudienceSocket.test.ts, src/page/AudienceSharePage/hooks/useAudienceShareState.ts, src/page/AudienceSharePage/hooks/useAudienceShareState.test.ts
CHAIRMAN_ABSENT 수신 시각을 별도로 기록합니다. 청중 상태는 서버 부재 알림 또는 연결 후 15초 동안 메시지가 없는 경우 사회자를 부재로 표시합니다.
라이브 공유 상태와 복구 UI
src/util/jwt.ts, src/util/jwt.test.ts, src/page/TimerPage/hooks/useLiveShare.ts, src/page/TimerPage/hooks/useLiveShare.test.ts, src/page/TimerPage/TimerPage.tsx, src/page/TimerPage/components/LiveShareButton.tsx, src/page/TimerPage/components/LiveShareButton.test.tsx, src/page/TimerPage/components/LiveShareButton.stories.tsx, src/page/TimerPage/components/LiveShareModal.tsx, src/page/TimerPage/components/LiveShareModal.test.tsx, src/page/TimerPage/components/LiveShareModal.stories.tsx, public/locales/en/translation.json, public/locales/ko/translation.json
JWT 만료 시각을 읽는 함수를 추가하고, 공유 중 만료 전 토큰 갱신과 만료된 토큰의 갱신 요청을 처리합니다. 다른 세션에 의해 교체되면 모달을 표시하며, 재시작 콜백으로 연결을 다시 시도합니다. 버튼은 공유 상태를 표시하고, 모달은 교체 안내와 재시작 버튼을 표시합니다.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ChairmanTab
  participant useChairmanSocket
  participant SocketManager
  participant Server
  participant useLiveShare
  participant LiveShareModal
  ChairmanTab->>useChairmanSocket: connect()
  useChairmanSocket->>SocketManager: subscribe with X-Chairman-Session
  SocketManager->>Server: subscribe to chairman channel
  Server-->>SocketManager: REPLACED notice
  SocketManager-->>useChairmanSocket: deliver notice
  useChairmanSocket->>SocketManager: disconnect()
  useChairmanSocket-->>useLiveShare: set isReplaced
  useLiveShare->>LiveShareModal: open replaced state
  LiveShareModal-->>useLiveShare: restartLiveShare()
  useLiveShare->>useChairmanSocket: connect with a new session ID
Loading

Suggested reviewers: i-meant-to-be

Merge Risk: ⚪ Minimal · up to db17d

No identified issue blocks merging after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 24 files. (2 skipped:… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 라이브 공유의 사회자 단일 세션 처리와 사회자 부재 처리를 명확하게 요약하며, 변경사항의 핵심 목적과 일치합니다.
Linked Issues check ✅ Passed 직접 연결된 이슈 [#496]의 코딩 요구사항을 구현했습니다. useChairmanSocket은 세션 ID를 구독과 발행 헤더에 포함하고, REPLACED 수신 시 현재 연결을 종료하며 isReplaced 상태를 제공합니다. useLiveShare는 자동 재연결을 막고 재시작 동작을 제공합니다. LiveShareButton은 활성 공유 상…
Out of Scope Changes check ✅ Passed 변경 사항은 [#496]의 단일 사회자 세션, 교체된 탭 처리, 활성 탭 표시, 청중의 사회자 부재 안내, 토큰 갱신, 소켓 헤더 지원 및 자동화 테스트에 직접 연결됩니다. 번역, Storybook 스토리, 타입 검증, 리스너 정리도 해당 기능의 사용자 안내와 검증 또는 지원 구현에 해당합니다. 요약된 변경에서 이슈와 무관한 기능 변경은 확인되지 않습니다.
Full details: Docstring Coverage

Explanation

Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 20 functions across 24 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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

🚀 Preview 배포 완료!

환경 URL
Preview 열기
API Dev 환경

PR이 닫히면 자동으로 정리됩니다.

@coli-geonwoo
coli-geonwoo merged commit 7338756 into develop Sep 24, 2026
3 checks passed
@github-actions

Copy link
Copy Markdown

🧹 Preview 배포가 정리되었습니다.

This branch was successfully deployed

2 active deployments
PREVIEW_ENV — db17d5fc Deployed Sep 24, 2026 by coli-geonwoo via cleanup #30
DEPLOY_DEV — db17d5fc Deployed Sep 24, 2026 by coli-geonwoo via build-and-deploy #182
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.

[FEAT] 라이브 공유 사회자 단일 세션 및 사회자 부재 처리

1 participant