Skip to content

Comments

Fix(client): FCM 연동 설정 로직 수정#163

Merged
jllee000 merged 4 commits intodevelopfrom
fix/#161/fcm-setting-edit
Sep 29, 2025
Merged

Fix(client): FCM 연동 설정 로직 수정#163
jllee000 merged 4 commits intodevelopfrom
fix/#161/fcm-setting-edit

Conversation

@jllee000
Copy link
Collaborator

@jllee000 jllee000 commented Sep 29, 2025

📌 Related Issues

관련된 Issue를 태그해주세요. (e.g. - close #25)

📄 Tasks

변경 사항

  • Firebase 설정 파일을 src에서 public으로 이동
    => Service Worker는 Vite 번들에 포함되지 않기 때문에 src 내부 모듈(firebase-config.ts)을 불러올 수 없음
  • Service Worker에서 Firebase SDK를 npm import 방식 → CDN import 방식으로 변경
    => Firebase SDK도 ESM import가 불가능하여, 공식 권장 방식인 CDN importScripts를 사용해야 함

이를 통해 Service Worker에서 Firebase Messaging 초기화 및 푸시 알림 처리 로직이 정상적으로 동작하도록 수정

⭐ PR Point (To Reviewer)

📷 Screenshot

Summary by CodeRabbit

  • 신기능
    • Firebase Cloud Messaging 기반 백그라운드 푸시 알림을 지원하여 알림 수신 신뢰성을 강화했습니다.
  • 버그 수정
    • 세션 만료 시 토큰 자동 갱신 및 오류 시 온보딩으로 복구해 로그인 상태 유지 안정성을 개선했습니다(웹/확장 프로그램).
    • 백그라운드 알림 표시 로직을 정비해 누락·지연 가능성을 줄였습니다.
  • 기타
    • 서비스 워커와 Firebase 리소스가 정상 제공되도록 라우팅 구성을 업데이트했습니다.
    • Firebase 초기화 구성 파일을 추가해 알림 및 관련 기능의 동작 기반을 마련했습니다.

@jllee000 jllee000 self-assigned this Sep 29, 2025
@jllee000 jllee000 added feat 기능 개발하라 개발 달려라 달려 fix 버그 수정하라 러브버그 labels Sep 29, 2025
@vercel
Copy link

vercel bot commented Sep 29, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
pinback-client-client Ready Ready Preview Comment Sep 29, 2025 3:16pm
pinback-client-landing Ready Ready Preview Comment Sep 29, 2025 3:16pm

@coderabbitai
Copy link

coderabbitai bot commented Sep 29, 2025

Walkthrough

FCM 서비스워커를 Firebase Messaging 전용 처리로 교체하고, 퍼블릭 firebase 설정 파일과 Vercel rewrites를 추가했습니다. 클라이언트·익스텐션의 Axios 요청 인터셉터는 토큰 갱신/온보딩 리다이렉트 흐름으로 리팩터링되었습니다. 온보딩 UI는 포매팅 변경만 포함됩니다.

Changes

Cohort / File(s) Summary
FCM 구성 및 서비스 워커
apps/client/public/firebase-config.js, apps/client/public/firebase-messaging-sw.js
퍼블릭 firebaseConfig 파일 추가. SW에서 importScripts로 Firebase compat SDK 로드, 앱 초기화 후 messaging.onBackgroundMessage로 백그라운드 알림 표시 로직으로 교체. 기존 push 이벤트/데이터 파싱 제거. 활성화 로그 문구 변경.
배포/리라이트 설정
apps/client/vercel.json
rewrites 재구성: /firebase-messaging-sw.js/firebase_sdk/(.*) 고정 매핑 추가 후, 최종적으로 /(.*)/index.html 캐치올 유지.
클라이언트 Axios 인터셉터(설정)
apps/client/src/shared/apis/setting/axiosInstance.ts
요청 인터셉터에 이메일 존재 시 리프레시 토큰 플로우 추가, 성공 시 Authorization 갱신. 실패 시 스토리지 정리 후 온보딩으로 리다이렉트. 401/403 대응은 갱신 플로우 전제.
익스텐션 Axios 인터셉터
apps/extension/src/apis/axiosInstance.ts
isNoAuth에 따라 Authorization 설정. 이메일 없으면 에러 처리 및 온보딩 유도. 토큰 획득 실패 시 스토리지 정리·리다이렉트 후 예외 전파. 기존의 무조건 토큰 세팅 로직 제거.
온보딩 UI 포매팅
apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx
공백/세미콜론 등 포매팅 변경만 적용, 동작 변화 없음.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as 브라우저(SW)
  participant FApp as Firebase App (SW)
  participant FCM as Firebase Messaging
  participant Reg as ServiceWorker Registration

  Note over User,FApp: SW 로드
  User->>FApp: importScripts + initializeApp(firebaseConfig)
  FApp->>FCM: getMessaging()
  FCM-->>User: onBackgroundMessage 등록

  Note over FCM,Reg: 백그라운드 메시지 수신
  FCM->>User: payload 전달
  User->>Reg: showNotification(title, options)
Loading
sequenceDiagram
  autonumber
  participant UI as 클라이언트/익스텐션
  participant AX as Axios 요청 인터셉터
  participant LS as localStorage/Storage
  participant Auth as refreshToken/fetchToken
  participant API as 서버 API
  participant OB as Onboarding Page

  UI->>AX: 요청 시작
  AX->>LS: email/token 조회
  alt 이메일 존재 (클라이언트)
    AX->>Auth: refreshToken(email)
    alt 성공
      Auth-->>AX: 새 토큰
      AX->>AX: Authorization 헤더 설정
      AX->>API: 요청 진행
    else 실패
      AX->>LS: 토큰/이메일 삭제
      AX->>OB: 리다이렉트
      AX-->>UI: 오류 전파
    end
  else 이메일 없음 또는 NoAuth(익스텐션)
    alt isNoAuth
      AX->>API: 토큰 없이 진행
    else 이메일 없음
      AX->>OB: 리다이렉트/에러
      AX-->>UI: 오류 전파
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

⚙️ Setting

Suggested reviewers

Poem

팝콘 같은 푸시가 톡톡, 밤하늘에 뜨네
새 SW는 살포시 받아, 제목·몸을 전하네
토큰은 상쾌히 갱신, 길 잃으면 온보딩으로 🧭
버니는 귀를 쫑긋 세워, 알림을 지킨다
hop hop, 안정된 밤을 위해 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning 링크된 이슈 #161에 대한 FCM 연동 수정 요구사항은 충족되었으나, 이 PR에서 실제로 진행된 변경사항에는 디자인 시스템의 Progress 컴포넌트 구현을 담은 #25 이슈의 요구사항이 전혀 포함되어 있지 않아 연결된 이슈 전체를 충족하지 못합니다. 해당 PR에서 다루는 변경사항과 관련 없는 #25 이슈 항목을 연결된 이슈 목록에서 제거하거나, Progress 컴포넌트 구현을 별도 PR로 분리하여 이슈 간 매핑을 명확히 조정해야 합니다.
Out of Scope Changes Check ⚠️ Warning 본 PR에서 FCM 연동 로직 수정이 주요 목표임에도 불구하고, apps/extension의 axiosInstance 리팩터링과 MainCard.tsx 스타일 변경 등 FCM 연관이 없는 코드 수정이 포함되어 있어 범위를 벗어난 변경이 발생했습니다. FCM 연동 수정과 직접 관련된 변경만 남기고, 나머지 확장(extension)용 Axios 리팩터링과 스타일 포맷 변경은 별도의 PR로 분리하여 리뷰 범위를 명확히 분리하는 것이 좋습니다.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed 제목 “Fix(client): FCM 연동 설정 로직 수정”은 본 PR의 주요 변경 사항인 FCM 설정 파일 이동 및 Service Worker 환경에서의 Firebase 초기화 방식 수정이라는 핵심을 명확히 요약하고 있으므로 적절합니다.
Description Check ✅ Passed PR 설명에는 관련 이슈 close #161와 작업 내역(설정 파일 이동, CDN importScripts 전환)을 명시한 Tasks 섹션이 잘 작성되어 있어 필수 정보가 충족되며, PR Point와 Screenshot 섹션은 템플릿 상 선택적이므로 전체적으로 대부분의 요구사항을 만족합니다.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/#161/fcm-setting-edit

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 and usage tips.

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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx (2)

13-15: Firebase 설정 모듈 import가 빌드 타임에 실패합니다.

public/firebase-config.js는 번들에 포함되지 않는 정적 에셋이라 ES 모듈 export가 제공되지 않습니다. 따라서 import { firebaseConfig } from '../../../../firebase-config'; 구문은 Vite/TS 컴파일 단계에서 해당 모듈을 찾지 못해 빌드가 깨집니다. React 쪽에서 사용할 설정은 src 영역에 export 가능한 모듈로 유지하거나, fetch('/firebase-config.js') 등 런타임 로딩 방식으로 분리해주세요. 현재 상태로는 온보딩 페이지가 로드되지 않습니다.


64-66: initializeApp를 렌더링 시마다 호출하면 바로 예외가 발생합니다.

컴포넌트가 상태 업데이트로 재렌더링될 때마다 initializeApp(firebaseConfig)가 다시 실행되어 Firebase App named '[DEFAULT]' already exists (app/duplicate-app) 예외가 터집니다. 초기화는 컴포넌트 외부나 getApps() 가드로 한 번만 수행하도록 바꿔주세요.

-import { initializeApp } from 'firebase/app';
+import { getApps, initializeApp, getApp } from 'firebase/app';-const app = initializeApp(firebaseConfig);
+const app = getApps().length > 0 ? getApp() : initializeApp(firebaseConfig);
🧹 Nitpick comments (5)
apps/client/public/firebase-messaging-sw.js (5)

14-19: importScripts 호출 순서 정리 및 config 선로딩

firebase.initializeApp 이전에 config를 로드해야 합니다. 또한 importScripts는 한 번에 여러 URL을 받을 수 있어 가독성이 좋아집니다.

적용 diff:

-importScripts(
-  'https://www.gstatic.com/firebasejs/9.22.2/firebase-app-compat.js'
-);
-importScripts(
-  'https://www.gstatic.com/firebasejs/9.22.2/firebase-messaging-compat.js'
-);
+importScripts(
+  '/firebase-config.js',
+  'https://www.gstatic.com/firebasejs/9.22.2/firebase-app-compat.js',
+  'https://www.gstatic.com/firebasejs/9.22.2/firebase-messaging-compat.js'
+);

추가 확인:

  • /firebase-config.js에서 const firebaseConfig = {...}가 전역 바인딩으로 들어오므로 SW 본문에서 바로 참조 가능합니다. 혹시 스코프 이슈가 있으면 self.firebaseConfig = {...}로 노출하도록 변경해 주세요.

5-5: Gitleaks 경고(API 키): Firebase Web API Key는 비밀값이 아니지만 방어선은 필요합니다.

Firebase Web API Key는 공개되어도 정상 동작을 전제로 하나, 보안을 위해 다음을 권장합니다:

  • Firestore/Storage/Functions 규칙 최소권한 설정
  • 도메인/앱 제한(가능한 리소스에 한함)
  • Gitleaks false-positive 억제(allowlist 패턴 추가) 또는 키 회전 절차 문서화

검증 스텝:

  • 콘솔의 보안 규칙/도메인 제한 현황 캡처 공유
  • Gitleaks 설정에 Firebase 키 허용 규칙 추가 여부 확인

25-27: activate 단계에 clients.claim() 추가로 즉시 제어권 확보

업데이트된 SW가 활성화 즉시 모든 클라이언트를 제어하도록 권장됩니다.

적용 diff:

 self.addEventListener('activate', function () {
   console.log('실행중..');
+  self.clients.claim();
 });

29-33: initializeApp 중복 초기화 가드

드물게 SW 재평가 시 중복 초기화를 방지하세요.

적용 diff:

-firebase.initializeApp(firebaseConfig);
+if (!firebase.apps || firebase.apps.length === 0) {
+  firebase.initializeApp(firebaseConfig);
+}
 
-const messaging = firebase.messaging();
+const messaging = firebase.messaging();

33-41: 배경 메시지 처리 보강: data-only/notification 혼용 대응 + 클릭 핸들러 + 로그 정리

FCM의 onBackgroundMessage는 주로 data-only 메시지에 발동합니다. payload.notification이 비어 있을 수 있으니 payload.data를 폴백으로 사용하고, 클릭 시 딥링크를 열도록 notificationclick 핸들러를 추가하세요. 프로덕션에서는 상세 payload 로깅을 피하는 것이 좋습니다.

적용 diff(해당 범위 내 수정):

-messaging.onBackgroundMessage((payload) => {
-  console.log('Received background message ', payload);
-
-  const notificationTitle = payload.notification?.title ?? '알림이 도착했어요!';
-  const notificationOptions = {
-    body: payload.notification?.body,
-  };
-  self.registration.showNotification(notificationTitle, notificationOptions);
-});
+messaging.onBackgroundMessage((payload) => {
+  const notification = payload?.notification || {};
+  const data = payload?.data || {};
+  const title =
+    notification.title || data.title || '알림이 도착했어요!';
+  const body = notification.body || data.body || '';
+  const icon = notification.icon || data.icon || '/icons/icon-192.png';
+  const url =
+    notification.click_action || data.click_action || data.url || '/';
+  const tag = data.tag;
+
+  self.registration.showNotification(title, {
+    body,
+    icon,
+    tag,
+    data: { url },
+  });
+});

추가(파일 하단 등 임의 위치에 새로 추가):

// 알림 클릭 시 기존 탭 포커스/네비게이션 또는 새 창 오픈
self.addEventListener('notificationclick', (event) => {
  const url = event.notification?.data?.url || '/';
  event.notification.close();
  event.waitUntil((async () => {
    const clientsList = await clients.matchAll({ type: 'window', includeUncontrolled: true });
    for (const client of clientsList) {
      // 이미 열려 있으면 포커스 + 네비게이트
      if ('focus' in client) {
        client.navigate(url);
        return client.focus();
      }
    }
    return clients.openWindow(url);
  })());
});

백엔드에서 실제로 "notification" 페이로드를 보내는지, "data-only"를 보내는지 확인해 주세요. 혼용 시 위 로직이 모두 대응합니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8dfcf37 and 883c486.

📒 Files selected for processing (6)
  • apps/client/public/firebase-config.js (1 hunks)
  • apps/client/public/firebase-messaging-sw.js (1 hunks)
  • apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx (3 hunks)
  • apps/client/src/shared/apis/setting/axiosInstance.ts (1 hunks)
  • apps/client/vercel.json (1 hunks)
  • apps/extension/src/apis/axiosInstance.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
apps/client/public/firebase-config.js (1)
apps/client/public/firebase-messaging-sw.js (1)
  • firebaseConfig (4-12)
apps/client/public/firebase-messaging-sw.js (1)
apps/client/public/firebase-config.js (1)
  • firebaseConfig (1-9)
apps/client/src/pages/onBoarding/components/funnel/MainCard.tsx (2)
apps/client/src/constants/alarms.ts (1)
  • AlarmsType (11-15)
apps/client/src/pages/onBoarding/utils/formatRemindTime.ts (1)
  • normalizeTime (1-26)
🪛 Gitleaks (8.28.0)
apps/client/public/firebase-config.js

[high] 2-2: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

apps/client/public/firebase-messaging-sw.js

[high] 5-5: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

🔇 Additional comments (1)
apps/client/public/firebase-messaging-sw.js (1)

4-12: storageBucket 형식 검증 완료 — 변경 불필요
Firebase 공식 문서에 따르면 최신 버전에서는 PROJECT_ID.firebasestorage.app 형식도 지원하므로, 현재 pinback-c55de.firebasestorage.app 설정은 유효합니다.

Comment on lines +4 to +12
const firebaseConfig = {
apiKey: 'AIzaSyD3KM0IQ4Ro3Dd2fyAY8fnhE1bQ_NesrBc',
authDomain: 'pinback-c55de.firebaseapp.com',
projectId: 'pinback-c55de',
storageBucket: 'pinback-c55de.firebasestorage.app',
messagingSenderId: '370851215931',
appId: '1:370851215931:web:08382b5e57808d29dcba1e',
measurementId: 'G-847ZNSCC3J',
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

firebaseConfig 하드코딩/중복 제거: public/firebase-config.js로 단일화하세요.

이미 apps/client/public/firebase-config.js가 존재하는데 SW에 동일 값을 하드코딩하면 드리프트 위험이 큽니다. SW에서는 동일 출처 스크립트를 importScripts('/firebase-config.js')로 불러 재사용하세요.

적용 diff(해당 범위 내 삭제만 포함):

-const firebaseConfig = {
-  apiKey: 'AIzaSyD3KM0IQ4Ro3Dd2fyAY8fnhE1bQ_NesrBc',
-  authDomain: 'pinback-c55de.firebaseapp.com',
-  projectId: 'pinback-c55de',
-  storageBucket: 'pinback-c55de.firebasestorage.app',
-  messagingSenderId: '370851215931',
-  appId: '1:370851215931:web:08382b5e57808d29dcba1e',
-  measurementId: 'G-847ZNSCC3J',
-};
+// firebaseConfig는 /firebase-config.js에서 주입됩니다.

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

🧰 Tools
🪛 Gitleaks (8.28.0)

[high] 5-5: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches.

(gcp-api-key)

🤖 Prompt for AI Agents
In apps/client/public/firebase-messaging-sw.js around lines 4 to 12, remove the
hardcoded firebaseConfig object (lines 4–12) and instead import the shared
config script from the same origin; replace the block with
importScripts('/firebase-config.js') and use the firebaseConfig value provided
by that script so the service worker reuses the single source of truth in
apps/client/public/firebase-config.js.

Comment on lines 15 to 19
'https://www.gstatic.com/firebasejs/9.22.2/firebase-app-compat.js'
);
importScripts(
'https://www.gstatic.com/firebasejs/9.22.2/firebase-messaging-compat.js'
);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

SDK 버전/호환 API 확인(compat onBackgroundMessage 지원 여부 포함)

  • 현재 9.22.2 고정. 최신 보안 패치 반영 및 compat에서 onBackgroundMessage 지원 상태를 문서로 재확인해 주세요. 필요 시 firebase/messaging/sw(모듈) 전환도 고려.

웹 검색 요청:


🌐 Web query:

- Firebase JS SDK 최신 안정 버전은?
- firebase messaging compat에서 service worker에서의 onBackgroundMessage 지원 여부(공식 문서).

💡 Result:

  • 최신 안정 Firebase JS SDK: v12.3.0 (릴리스 노트 기준, 2025-09-18). [1]

  • firebase-messaging compat에서 서비스 워커의 onBackgroundMessage 지원 여부: 지원합니다. 공식 문서에는 service worker에서 importScripts로 firebase-app-compat.js / firebase-messaging-compat.js를 불러와 firebase.messaging()을 사용하고 messaging.onBackgroundMessage(...)를 등록하는 예제가 있습니다. [2]

참고문헌
[1] Firebase JavaScript SDK Release Notes.
[2] Receive messages using Firebase Cloud Messaging — Web (서비스 워커 + compat 예제).


Firebase SDK 버전 상향 및 모듈 전환 검토

  • Firebase JS SDK를 9.22.2에서 최신 안정 버전(12.3.0, 2025-09-18 기준)으로 상향 적용하세요.
  • firebase-messaging-compat는 service worker에서 onBackgroundMessage를 지원하므로, 현 코드에서도 백그라운드 메시지 처리가 가능합니다.
  • 장기적 보안 패치 및 트리 셰이킹, 타입 지원을 위해 모듈형 SDK(firebase/messaging/sw) 전환을 검토하세요.
🤖 Prompt for AI Agents
In apps/client/public/firebase-messaging-sw.js around lines 15 to 19, the
service-worker is importing Firebase SDK v9.22.2 and the compat messaging
bundle; update the imports to a current stable SDK (e.g., 12.3.0) and either (a)
swap the importScripts URLs to the newer compat bundles so your existing
onBackgroundMessage code continues to work, or (b) migrate the service-worker to
the modular service-worker bundle (firebase/messaging/sw) by replacing the
import with the modular sw script and adapting the messaging API calls to the
modular names and initialization flow; ensure you update any API usage in the
file to match the chosen bundle (compat vs modular) and test background message
handling after the change.

@github-actions
Copy link

✅ Storybook chromatic 배포 확인:
🐿️ storybook

@jllee000 jllee000 merged commit 356dfdb into develop Sep 29, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 기능 개발하라 개발 달려라 달려 fix 버그 수정하라 러브버그

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Fix] FCM 커스텀 및 연동 수정

1 participant