[feat] 지원자 상태 변경 SSE 실시간 동기화 구현#1062
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | 변경 사항 요약 |
|---|---|
의존성frontend/package.json |
런타임 의존성 eventsource (^4.1.0) 추가 |
SSE API 계층frontend/src/apis/club.ts |
`createApplicantSSE(applicationFormId, callbacks): EventSource |
타입 정의frontend/src/types/applicants.ts |
ApplicantStatusEvent, ApplicantSSECallbacks 인터페이스 추가 (applicantId, status, memo, timestamp, clubId, applicationFormId, onStatusChange, onError) |
컨텍스트 변경frontend/src/context/AdminClubContext.tsx |
applicationFormId 상태 및 setApplicationFormId 노출; SSE 구독/정리 useEffect 추가; applicantsData를 status/memo 변경에 따라 불변 업데이트 |
탭 연동frontend/src/pages/AdminPage/tabs/ApplicantsTab/* |
ApplicantsTab에서 setApplicationFormId(formId) 호출 및 컴포넌트 언마운트 시 null로 정리 |
Detail 페이지 조정frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage.tsx |
effect 의존성에 applicant?.status, applicant?.memo 추가 (필드 변경 시 재실행 보장) |
Sequence Diagram(s)
sequenceDiagram
participant User as 사용자
participant ApplicantsTab as ApplicantsTab
participant AdminClubContext as AdminClubContext
participant API as createApplicantSSE
participant Server as 서버(SSE 엔드포인트)
participant ApplicantDetail as ApplicantDetailPage
User->>ApplicantsTab: 지원자 탭 방문
ApplicantsTab->>AdminClubContext: setApplicationFormId(formId)
AdminClubContext->>API: createApplicantSSE(formId, callbacks)
API->>Server: EventSource 연결 (Bearer 토큰, credentials)
Server-->>API: SSE 연결 수립
loop 상태 변경 발생
Server-->>API: applicant-status-changed 이벤트 (JSON)
API->>AdminClubContext: callbacks.onStatusChange(event)
AdminClubContext->>AdminClubContext: applicantsData 업데이트 (status/memo)
AdminClubContext-->>ApplicantsTab: 컨텍스트 업데이트 전파
AdminClubContext-->>ApplicantDetail: 컨텍스트 업데이트 전파
ApplicantDetail->>ApplicantDetail: status/memo 변경 감지 및 UI 갱신
end
User->>ApplicantsTab: 탭 이탈
ApplicantsTab->>AdminClubContext: setApplicationFormId(null)
AdminClubContext->>API: EventSource 연결 종료
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
- [Feature] 지원자의 지원서 상태를 실시간으로 공유한다. #791 — 백엔드 SSE 엔드포인트 및
applicant-status-changed이벤트 구현과 프론트 SSE 클라이언트 연동 측면에서 직접 관련. - [release] v1.1.0 #676 — 프론트 타입 정의(
ApplicationStatus등) 변경과 겹쳐 타입 호환성 검토가 필요함. - [feature] 사용자가 지원하기를 눌렀을때 지원가능한 지원서들이 모달로 뜬다 #787 — AdminClubContext에 applicationFormId 관련 변경을 포함하므로 컨텍스트 API 충돌 가능성 있음.
Suggested labels
📬 API
Suggested reviewers
- Zepelown
- seongwon030
- oesnuj
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | PR 제목이 변경 사항의 주요 내용인 SSE 실시간 동기화 구현을 명확하게 반영하고 있습니다. |
| Linked Issues check | ✅ Passed | PR이 MOA-296의 모든 주요 요구사항을 충족합니다: SSE 이벤트 연결 구현, 모집 상태 실시간 업데이트, 메모 필드 업데이트가 모두 포함되어 있습니다. |
| Out of Scope Changes check | ✅ Passed | 모든 변경 사항이 SSE 실시간 동기화 구현이라는 범위 내에 있으며, MOA-296의 요구사항과 관련된 변경만 포함되어 있습니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing touches
- 📝 Generate docstrings
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@frontend/src/apis/club.ts`:
- Around line 88-134: The createApplicantSSE function currently captures
accessToken once and returns the original EventSource while its onerror
reconnects to a new instance (causing leaked/uncloseable sources, stale tokens,
and unlimited retries); fix by not performing automatic internal reconnect with
a new EventSource that the caller doesn't hold—instead change
createApplicantSSE(connect) to create and return a single EventSource instance
and remove its internal onerror reconnection, or accept a tokenProvider callback
and a reconnect policy so reconnection is controlled by the caller; specifically
update createApplicantSSE / connect / eventSource to (1) obtain Authorization
via a provided tokenProvider() at connect time (not closed-over localStorage
value), (2) stop replacing the returned eventSource from inside source.onerror
(or if you keep internal reconnect, ensure eventSource is updated and previous
source closed and returned to caller), and (3) implement a retry
limit/exponential backoff (MAX_RETRIES) so onerror does not retry indefinitely.
- Around line 92-93: The code captures accessToken once at the top of
createApplicantSSE which causes stale tokens to be used for long-lived SSE
connections; instead, inside the fetch callback used to open/reconnect the SSE
(i.e., the fetch/eventSource initiation logic within createApplicantSSE), call
localStorage.getItem('accessToken') each time before making the request and set
the Authorization header from that fresh value, handling the null case there
(e.g., abort/retry or throw) rather than returning early from the outer
function; remove the top-level accessToken capture and any early return that
uses it so token lookup is dynamic per connection attempt.
🧹 Nitpick comments (1)
frontend/src/pages/AdminPage/tabs/ApplicantsTab/ApplicantDetailPage/ApplicantDetailPage.tsx (1)
60-65: 의존성 배열의 중복 항목
applicant?.status와applicant?.memo는 중복된 의존성입니다. Context에서 SSE 이벤트 수신 시applicant객체를 불변하게 업데이트하므로 ({ ...applicant, status, memo }),applicant참조 자체가 변경됩니다. 따라서applicant만 의존성으로 두어도 동일하게 동작합니다.♻️ 의존성 배열 단순화 제안
useEffect(() => { if (applicant) { setAppMemo(applicant.memo); setApplicantStatus(mapStatusToGroup(applicant.status).status); } - }, [applicant, applicant?.status, applicant?.memo]); + }, [applicant]);
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@frontend/src/context/AdminClubContext.tsx`:
- Around line 74-100: The onError handler inside the sseConnect setup can
schedule multiple reconnect timeouts if errors fire repeatedly; modify the
onError in createApplicantSSE (used by sseConnect in the useEffect) to clear any
existing reconnectTimeoutRef.current before calling setTimeout so only one
reconnect timer is active; ensure reconnectTimeoutRef is set to the new timeout
ID and left cleared on cleanup (you’ll touch eventSourceRef,
reconnectTimeoutRef, sseConnect, createApplicantSSE and the onError callback to
implement this).
- Around line 38-43: The ref type for reconnect timeout uses NodeJS.Timeout
which conflicts with browser DOM types; update the reconnectTimeoutRef
declaration to use a DOM-safe timeout type by replacing NodeJS.Timeout with
ReturnType<typeof setTimeout> (i.e. change the type used in the
reconnectTimeoutRef useRef call), keeping the EventSource ref and
applicationFormId state unchanged so the symbol reconnectTimeoutRef is the only
edit required.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@frontend/src/apis/club.ts`:
- Around line 94-97: The connect function currently returns null silently when
localStorage.getItem('accessToken') is falsy; instead, invoke the SSE error
handling so the upper-level reconnection/login flow can act. Modify connect to
detect missing accessToken and call the existing onError handler (e.g.,
onError(new Error('Missing accessToken')) or similar) with a clear Error before
returning null, referencing the connect function, accessToken variable, and
EventSource/onError handler so the reconnection logic is triggered rather than
silently stopping.
#️⃣ 연관된 이슈
#798
📝 작업 내용
SSE(Server-Sent Events)를 활용한 지원자 상태 실시간 동기화 기능 구현
2026-01-18.00.07.59.mov
지원자 상태 변경 시 실시간으로 UI에 반영되도록 SSE 연결 기능을 구현했습니다.
주요 변경사항
eventsource라이브러리 도입EventSource는 커스텀 헤더(Authorization)를 지원하지 않아,eventsource라이브러리(v4.1.0)를 도입SSE 연결 함수 구현 (createApplicantSSE)
applicant-status-changed이벤트 리스닝AdminClubContext 내 SSE 연결 핸들링
SSE 타입 정의
ApplicantSSECallbacks,ApplicantStatusEvent타입 추가🫡 참고사항
EventSource는 커스텀 헤더를 지원하지 않아eventsource라이브러리를 사용했습니다applicant-status-changed이벤트를 발송하면 프론트엔드에서 해당 지원자 정보가 자동 갱신됩니다Summary by CodeRabbit
새로운 기능
기타
✏️ Tip: You can customize this high-level summary in your review settings.