Skip to content

Conversation

@layout-SY
Copy link
Collaborator

@layout-SY layout-SY commented May 29, 2025

구현내용

  • 실시간 알림에서 SSE 연결이 모종의 이유로 서비스 실행 도중 모든 API 요청을 다운 시키는 문제 발생.
  • 정확하게 확인 되진 않았지만, SSE 헤더에 인증 토큰을 추가 하기 위해 적용한 event-source-polyfill 라이브러리가 요청 커넥션 풀을 전부 pending 하게 되어 다른 요청이 이루어지지 않았던 것으로 보임
  • 따라서 해당 방식을 제외하고, 파라미터로 인증 토큰을 추가하여 보내는 것으로 변경
  • 혹시 Header에서 SSE 관련 코드를 실행하게 되어 언마운트 될 때마다 재연결 되는 부분이 문제일 수 있다 판단하여 전역에서 SSE를 실행하도록
    하고, 실시간 알림 데이터를 contextAPI를 통해 전역에서 관리
  • 아직 명확한 이유는 모르겠음.

연관이슈

close #310

Summary by CodeRabbit

  • 신규 기능

    • 알림 벨 및 드롭다운 UI가 완전히 통합되어 실시간 알림 신호를 표시하고 관리할 수 있습니다.
    • 실시간 알림 관리를 위한 컨텍스트 기반 상태 관리 기능이 추가되었습니다.
    • 알림 초기화 및 제공 컴포넌트가 도입되어 앱 전체에서 실시간 알림 수신이 가능해졌습니다.
  • 리팩터

    • 실시간 알림 관련 로직이 컨텍스트와 훅 기반으로 구조화되어 유지보수성과 확장성이 향상되었습니다.
  • 버그 수정

    • 알림 신호 수신 및 표시 과정에서 발생할 수 있는 CORS 문제를 해결하였습니다.

@layout-SY layout-SY self-assigned this May 29, 2025
@layout-SY layout-SY added 🛠개선 성능 개선/리팩토링에 대한 라벨 👀버그 버그 labels May 29, 2025
@coderabbitai
Copy link

coderabbitai bot commented May 29, 2025

"""

Walkthrough

실시간 알림 기능이 컨텍스트 기반으로 리팩토링되었습니다. 알림 상태와 관련 함수들이 SseContext를 통해 전역에서 관리되며, 알림 벨 UI와 드롭다운이 완전히 통합되었습니다. 라우트 루트에 알림 및 토스트 프로바이더가 추가되어 전체 앱에서 알림 기능이 활성화됩니다.

Changes

파일/경로 변경 요약
src/components/common/header/Header.tsx 알림 벨 및 드롭다운 UI, 알림 컨텍스트 연동, 라이브 알람 테스트 호출 복원
src/components/user/notificationLive/NotificationInitializer.tsx 알림 훅을 호출하는 새 컴포넌트 추가
src/components/user/notificationLive/NotificationProvider.tsx 알림 상태 관리 및 컨텍스트 프로바이더 컴포넌트 추가
src/context/SseContext.tsx 알림 컨텍스트 및 커스텀 훅 추가
src/hooks/user/useNotification.ts 알림 훅이 컨텍스트 기반으로 리팩토링, EventSource 초기화 개선
src/routes/AppRoutes.tsx 루트에 알림/토스트 프로바이더 및 알림 이니셜라이저 추가, 라우터 구조 변경

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Header
    participant NotificationProvider
    participant useNotification
    participant SseContext

    User->>Header: 페이지 진입
    Header->>SseContext: useNotificationContext()로 signalData 접근
    User->>NotificationProvider: 앱 루트에서 감쌈
    NotificationProvider->>SseContext: signalData/clearSignal/setSignal 제공
    NotificationProvider->>useNotification: NotificationInitializer 통해 훅 실행
    useNotification->>SseContext: setSignal로 실시간 알림 데이터 갱신
    Header->>SseContext: 알림 벨 클릭 시 clearSignal 호출
    SseContext->>Header: signalData 업데이트 시 UI 반영
Loading

Assessment against linked issues

Objective Addressed Explanation
SSE 링크가 pending 상태로 유지되어 서버 요청이 실패하는 버그 해결 (#310)
공고 상세의 댓글 컴포넌트 대댓글 입력창 스타일 버그 수정 (#310) 관련 코드 변경이 본 PR에 포함되지 않음

Poem

🐰
실시간 알림이 다시 살아났네,
컨텍스트 품에 벨이 울리네!
SSE 버그는 안녕,
토스트와 함께 반짝이는 소식 전해,
토끼는 오늘도 깡총깡총 춤을 추네!

(띠링! 알림이 도착했습니다.)
"""

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-05-29T13_47_18_881Z-debug-0.log


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08969a5 and da0a3f8.

📒 Files selected for processing (2)
  • src/components/common/header/Header.tsx (3 hunks)
  • src/hooks/user/useNotification.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/common/header/Header.tsx
  • src/hooks/user/useNotification.ts
✨ 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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
src/context/SseContext.tsx (1)

1-17: 잘 구현된 컨텍스트 구조입니다.

SSE 알림 관리를 위한 컨텍스트가 깔끔하게 설계되었습니다. 타입 안전성과 기본값 설정이 적절합니다.

향후 개선을 위한 제안: 에러 상태나 로딩 상태도 컨텍스트에 포함하는 것을 고려해보세요.

export interface SseContextProps {
  signalData: AlarmLive | null;
+ isConnecting?: boolean;
+ error?: string | null;
  clearSignal: () => void;
  setSignal: (data: AlarmLive | null) => void;
}
src/hooks/user/useNotification.ts (2)

29-35: EventSource 생성 방식 개선과 보안 고려사항

CORS preflight 문제 해결을 위한 접근은 적절하지만, 몇 가지 개선점이 있습니다:

  1. 삼항 연산자 단순화: 라인 33의 accessToken ? accessToken : ''accessToken || ''로 단순화할 수 있습니다.

  2. URL 파라미터 보안 고려: 액세스 토큰을 URL 파라미터로 전송하면 서버 로그에 노출될 수 있습니다. 가능하다면 서버 측에서 쿠키 기반 인증을 고려해보세요.

-        `${import.meta.env.VITE_APP_API_BASE_URL}user/sse?accessToken=${
-          accessToken ? accessToken : ''
-        }`
+        `${import.meta.env.VITE_APP_API_BASE_URL}user/sse?accessToken=${accessToken || ''}`

39-42: 프로덕션 코드에서 console.log 제거 필요

개발 중 디버깅을 위한 console.log 문들이 남아있습니다. 프로덕션 배포 전에 제거해주세요.

-      eventSource.onopen = () => {
-        console.log('확인');
-        console.log(eventSource.readyState);
-      };
+      eventSource.onopen = () => {
+        // SSE connection established successfully
+      };
-          console.log(eventData);

Also applies to: 48-48

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 72ff949 and 08969a5.

📒 Files selected for processing (6)
  • src/components/common/header/Header.tsx (3 hunks)
  • src/components/user/notificationLive/NotificationInitializer.tsx (1 hunks)
  • src/components/user/notificationLive/NotificationProvider.tsx (1 hunks)
  • src/context/SseContext.tsx (1 hunks)
  • src/hooks/user/useNotification.ts (2 hunks)
  • src/routes/AppRoutes.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/context/SseContext.tsx (1)
src/models/alarm.ts (1)
  • AlarmLive (28-33)
src/components/user/notificationLive/NotificationProvider.tsx (2)
src/models/alarm.ts (1)
  • AlarmLive (28-33)
src/context/SseContext.tsx (1)
  • SseContext (10-14)
src/components/common/header/Header.tsx (3)
src/context/SseContext.tsx (1)
  • useNotificationContext (16-16)
src/util/formatImgPath.ts (1)
  • formatImgPath (1-4)
src/api/alarm.api.ts (1)
  • testLiveAlarm (38-49)
src/hooks/user/useNotification.ts (4)
src/hooks/useToast.ts (1)
  • useToast (4-7)
src/context/SseContext.tsx (1)
  • useNotificationContext (16-16)
src/models/alarm.ts (1)
  • AlarmLive (28-33)
src/hooks/queries/user/keys.ts (1)
  • AlarmList (31-33)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: accessibility-test
🔇 Additional comments (7)
src/components/user/notificationLive/NotificationProvider.tsx (1)

5-16: 컨텍스트 프로바이더가 올바르게 구현되었습니다.

상태 관리와 함수 정의가 깔끔하고, React 컨텍스트 패턴을 적절히 따르고 있습니다.

src/routes/AppRoutes.tsx (1)

387-402:

Details

✅ Verification successful

라우팅 구조 변경이 전역 컨텍스트 제공에 적합합니다.

createBrowserRouter와 루트 래퍼를 사용한 구조 변경으로 알림 시스템이 앱 전체에서 사용 가능해졌습니다. 프로바이더 순서와 Outlet 패턴 사용이 적절합니다.

기존 중첩 라우팅이 새로운 구조에서도 정상 작동하는지 확인해주세요.


🏁 Script executed:

#!/bin/bash
# 중첩 라우팅이 있는 라우트들 확인
rg -A 3 "children:" src/routes/AppRoutes.tsx

Length of output: 1014


중첩 라우팅 정상 동작 확인 완료

  • rg -A 3 "children:" src/routes/AppRoutes.tsx 결과, 기존의 모든 중첩된 children 배열이 유지되어 있음을 확인했습니다.
  • newRouteList에 기존 라우트 정의가 포함되어 있고, 루트 레벨에 { path: '*', element: <NotFoundPage /> }가 추가된 구조로, 와일드카드 404 처리도 올바르게 적용됩니다.
  • Outlet 패턴하에 프로바이더 래퍼(NotificationProvider, ToastProvider, NotificationInitializer)가 앱 전역에 정상적으로 적용될 것으로 보입니다.

위 확인 결과를 바탕으로 변경된 라우터 설정을 승인합니다.

src/hooks/user/useNotification.ts (2)

1-1: 컨텍스트 기반 접근 방식으로의 전환이 적절합니다.

새로운 useNotificationContext 훅을 통해 전역 상태 관리로 전환하는 것이 올바른 접근입니다.

Also applies to: 7-7


14-14: 컨텍스트에서 필요한 함수만 구조분해할당하는 것이 좋습니다.

전역 상태 관리를 위해 setSignal 함수를 올바르게 가져오고 있습니다.

src/components/common/header/Header.tsx (3)

14-20: 알림 기능 관련 임포트 복원이 적절합니다.

실시간 알림 시스템 구현에 필요한 모든 컴포넌트와 훅들이 올바르게 임포트되었습니다.


30-30: 컨텍스트에서 필요한 상태와 함수를 올바르게 가져오고 있습니다.

signalDataclearSignal을 통해 알림 상태 관리가 적절히 구현되었습니다.


62-78: 알림 벨 UI 통합이 잘 구현되었습니다.

로그인 상태에 따른 조건부 렌더링, 새 알림 표시를 위한 점 표시, 클릭 시 알림 클리어 기능이 모두 적절히 구현되었습니다. 접근성 속성도 잘 유지되었습니다.

Comment on lines +3 to +7
const NotificationInitializer = () => {
useNotification();

return null;
};
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

초기화 컴포넌트 패턴이 적절합니다.

전역 SSE 연결 초기화를 위한 깔끔한 접근 방식입니다.

useNotification 훅에서 SSE 연결의 적절한 정리(cleanup)가 이루어지는지 확인해주세요. EventSource 연결이 컴포넌트 언마운트 시 제대로 닫히지 않으면 메모리 누수가 발생할 수 있습니다.


🏁 Script executed:

#!/bin/bash
# useNotification 훅에서 EventSource cleanup 확인
ast-grep --pattern $'useEffect(() => {
  $$$
  return () => {
    $$$
  }
}, $$$)'

Length of output: 3614


useNotification 훅 정의 위치와 EventSource 사용 여부를 확인하기 위해 다음 스크립트를 실행해주세요:


🏁 Script executed:

#!/bin/bash
# useNotification 훅이 정의된 파일 찾기
rg "useNotification" -n src

# EventSource 인스턴스 생성 및 cleanup 확인
rg "EventSource" -n src

Length of output: 1094


useNotification 훅의 useEffect 내부를 확인하기 위해 아래 스크립트를 실행해주세요:


🏁 Script executed:

#!/bin/bash
# useNotification.ts의 useEffect 블록 및 EventSource close 호출 여부 확인
rg "useEffect" -n src/hooks/user/useNotification.ts -A20 -B5

Length of output: 1413


useNotification 훅의 전체 cleanup 로직을 확인하기 위해 아래 스크립트를 실행해주세요:


🏁 Script executed:

#!/bin/bash
# useNotification.ts의 return cleanup 블록 확인
rg "return \\(\\) =>" -n src/hooks/user/useNotification.ts -A20 -B5

Length of output: 67


useNotification 훅의 useEffect 전체 블록(cleanup 반환 함수 포함)을 확인하기 위해 아래 스크립트를 실행해주세요:


🏁 Script executed:

#!/bin/bash
# useNotification.ts의 useEffect 블록 전체 출력 (cleanup 포함)
rg "useEffect" -n src/hooks/user/useNotification.ts -A150 -B5

Length of output: 2278


useNotification 훅에 SSE 연결 정리(cleanup) 로직 추가가 필요합니다.

현재 useEffect 내부에 EventSource를 생성만 하고, 컴포넌트 언마운트 시나 의존성 변경 시 연결을 닫는 반환 함수가 없습니다. 이로 인해 메모리 누수가 발생할 수 있습니다.

다음 부분에 cleanup 반환 함수를 추가해주세요.

  • 파일: src/hooks/user/useNotification.ts
  • 위치: useEffect(() => { … }, [queryClient, userId]); 내부 끝부분

예시 수정안:

   useEffect(() => {
     if (!userId) {
       if (eventSourceRef.current) {
         eventSourceRef.current.close();
         eventSourceRef.current = null;
       }
       return;
     }

     if (eventSourceRef.current) {
       return;
     } else {
       const eventSource = new EventSource(/* … */);
       eventSourceRef.current = eventSource;
       // 이벤트 핸들러 등록…
     }

+    // 컴포넌트 언마운트 또는 userId/queryClient 변경 시 SSE 연결 닫기
+    return () => {
+      if (eventSourceRef.current) {
+        eventSourceRef.current.close();
+        eventSourceRef.current = null;
+      }
+    };
   }, [queryClient, userId]);

위 변경으로 언마운트 시점 및 의존성 변경 시 EventSource가 정상적으로 종료됩니다.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/hooks/user/useNotification.ts around the useEffect block with
dependencies [queryClient, userId], the EventSource connection is created but
lacks a cleanup function to close it on component unmount or dependency change.
To fix this, add a return cleanup function inside the useEffect that calls
EventSource.close() to properly close the connection and prevent memory leaks.

Comment on lines 44 to 46
useEffect(() => {
testLiveAlarm();
}, []);
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

프로덕션에서 자동 테스트 알림 호출 확인 필요

헤더 컴포넌트가 마운트될 때마다 testLiveAlarm()이 자동으로 호출됩니다. 이는 프로덕션 환경에서 의도하지 않은 알림을 발송할 수 있습니다.

개발/테스트 환경에서만 실행되도록 제한하거나, 다른 트리거 방식을 고려해보세요.

다음 스크립트로 다른 컴포넌트에서도 비슷한 패턴이 있는지 확인해보겠습니다:


🏁 Script executed:

#!/bin/bash
# testLiveAlarm 함수의 다른 사용처 확인
rg -A 3 -B 3 "testLiveAlarm"

Length of output: 1278


❗ 프로덕션 환경 자동 테스트 알람 호출 차단 필요

헤더 컴포넌트가 마운트될 때마다 testLiveAlarm()을 무조건 호출하고 있어, 프로덕션 배포 시 의도치 않게 알림이 발송될 수 있습니다. 개발/테스트 환경에서만 동작하도록 환경 변수를 체크하거나 별도 플래그로 제어하세요.

수정 위치:

  • src/components/common/header/Header.tsx:44-46

제안 변경:

 useEffect(() => {
-  testLiveAlarm();
+  if (process.env.NODE_ENV === 'development') {
+    testLiveAlarm();
+  }
 }, []);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
useEffect(() => {
testLiveAlarm();
}, []);
// src/components/common/header/Header.tsx
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
testLiveAlarm();
}
}, []);
🤖 Prompt for AI Agents
In src/components/common/header/Header.tsx around lines 44 to 46, the useEffect
hook calls testLiveAlarm() unconditionally on component mount, which can trigger
unwanted alerts in production. Modify the code to check the environment before
calling testLiveAlarm(), ensuring it only runs in development or test
environments by using environment variables or a feature flag to conditionally
execute the function.

@layout-SY layout-SY requested a review from YouD0313 May 31, 2025 12:43
@layout-SY layout-SY merged commit 3f6df80 into develop Jun 1, 2025
4 checks passed
@layout-SY layout-SY deleted the bug/#310 branch June 1, 2025 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

👀버그 버그 🛠개선 성능 개선/리팩토링에 대한 라벨

Projects

None yet

Development

Successfully merging this pull request may close these issues.

실시간 알림 버그 해결

3 participants