Firebase PWA에서 알림 센터 구축하기

영업 팀을 관리하려면 많은 도구가 필요합니다. 제가 사용한 제어 패널에는 FCM 푸시 알림, 채팅, 리마인더, 공유 캘린더가 포함되어 있었습니다.

문제는 이 도구들이 각각 분리된 섬처럼 존재했다는 점입니다. 운영자는 휴가 신청이나 메시지를 확인하기 위해 여러 섹션을 번갈아 가며 이동해야 했습니다. 모든 것을 한눈에 볼 수 있는 단일 공간이 없었습니다.

그래서 저는 알림 센터를 구축했습니다. 모든 관련 이벤트를 하나의 타임라인으로 보여주는 공간입니다.

Firebase 활용 방법

저는 Firestore와 Realtime Database(RTDB)를 모두 사용합니다. 각각의 용도가 다릅니다.

Firestore (이력 관리용): 휴가 신청과 같이 변경되지 않는 데이터에는 .get()을 사용합니다. 영구적인 리스너가 필요 없으므로 비용을 낮게 유지할 수 있습니다. • RTDB (실시간 데이터용): 채팅, 리마인더, 캘린더 이벤트에는 .on('value')를 사용합니다. 이러한 노드는 크기가 작고 즉각적인 반응이 필요합니다.

잘못된 선택은 Firebase 청구서에 즉각적으로 나타납니다.

기술적 난관들

UI를 구축하면서 세 가지 주요 문제를 해결해야 했습니다.

1. 모바일 사용성

필터 칩(filter chips)에 flex-wrap: wrap을 사용했습니다. 초기 버전은 가로 스크롤 방식을 사용했는데, 모바일에서는 사용자가 칩을 볼 수 없었고 스크롤이 가능하다는 사실도 알지 못했습니다. 이를 두 줄로 감싸도록 수정하여 문제를 해결했습니다.

2. CSS 위치 지정(Positioning)

패널을 document.body에 직접 추가했습니다. overflow:hidden이 설정된 컨테이너 안에 fixed 요소를 중첩시키면 위치 지정이 깨지기 때문입니다.

3. 세션 복구 버그

프로덕션 환경에서 "로그인 상태 유지"를 사용하는 사용자들이 빈 패널을 보는 현상이 발생했습니다. 초기화 코드가 수동 로그인 시에만 실행되고, 세션이 복구될 때는 실행되지 않았기 때문입니다.

알림 센터가 항상 로드되도록 세 가지 폴백(fallback) 단계를 구현했습니다:

  • 로그인 함수에 래퍼(wrapper) 적용.
  • 500ms마다 사용자를 확인하는 폴링(polling) 루프.
  • 사용자 프로필이 화면에 나타나는지 감시하는 MutationObserver.

성공적인 설계 사례

  • 사용자별 읽음 상태를 추적하기 위해 localStorage 사용.
  • 복잡한 쿼리를 위해 Firestore에서 복합 인덱스(composite indexes) 사용.
  • 모바일에서 fixed 요소가 상단 바를 가리지 않도록 미디어 쿼리 사용.

아키텍처가 중요합니다. 로그에는 Firestore를, 실시간 업데이트에는 RTDB를 사용하세요.

출처: https://dev.to/androve2k/building-a-notification-center-in-a-firebase-pwa-firestore-vs-rtdb-and-three-bootstrap-fallback-5feb