Skip to content

Notification Flow

l2juhan edited this page Apr 18, 2026 · 2 revisions

알림 기능 플로우 (Notification Flow)

인앱 알림, 푸시 알림, 알림 설정에 대한 전체 플로우를 설명합니다.


1. 개요

항목 내용
대상 사용자 WORKER, EMPLOYER 공통
인앱 알림 SSE 실시간 구독 + Header 벨 아이콘 뱃지
푸시 알림 FCM 토큰 기반 (앱 백그라운드/종료 시)
API 모듈 src/api/notification/

2. 알림 시스템 구조

┌─────────────────────────────────────────────────────────────────┐
│                      알림 시스템 구조                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [앱 Foreground]                                                │
│      │                                                          │
│      ├─→ SSE 구독 (/api/notifications/stream)                   │
│      │     → 새 알림 수신 시 unreadCount 증가                    │
│      │     → Header 벨 아이콘에 숫자 뱃지 표시 (1~9, 10+→"9+") │
│      │                                                          │
│      └─→ 벨 아이콘 클릭 → NotificationPopup (최근 5개)          │
│            → "전체 보기" → NotificationScreen                   │
│                                                                 │
│  [앱 Background/종료]                                            │
│      │                                                          │
│      ├─→ FCM 푸시 알림 (OS 알림센터에 표시)                      │
│      │                                                          │
│      └─→ 알림 탭 → 딥링크 네비게이션 (actionType 기반)           │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

3. SSE 실시간 알림 구독

┌─────────────────────────────────────────────────────────────────┐
│                    SSE 실시간 구독 플로우                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [로그인 성공]                                                   │
│      │                                                          │
│      ▼                                                          │
│  useNotificationStream() 활성화                                  │
│      │                                                          │
│      ├─→ GET /api/notifications/unread-count                     │
│      │     → 초기 읽지 않은 알림 수 → notificationStore 저장     │
│      │                                                          │
│      └─→ SSE 연결 (/api/notifications/stream)                   │
│            → XMLHttpRequest 기반 (React Native 호환)             │
│            → 연결 끊김 시 5초 후 자동 재연결                     │
│            → 새 이벤트 수신 시 incrementUnreadCount()             │
│                                                                 │
│  [로그아웃/언마운트]                                              │
│      │                                                          │
│      ▼                                                          │
│  SSE 연결 해제                                                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

notificationStore (Zustand)

interface NotificationStoreState {
  unreadCount: number;
  setUnreadCount: (count: number) => void;
  incrementUnreadCount: () => void;
  decrementUnreadCount: () => void;
}

4. FCM 토큰 등록/삭제

┌─────────────────────────────────────────────────────────────────┐
│                    FCM 토큰 관리 플로우                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [로그인 성공]                                                   │
│      │                                                          │
│      ▼                                                          │
│  useFcmToken() 활성화                                            │
│      │                                                          │
│      ▼                                                          │
│  GET /api/settings/me → pushEnabled 조회 (2026-03-09 변경)       │
│      │                                                          │
│      ├─→ pushEnabled: false → 토큰 등록하지 않음                 │
│      │                                                          │
│      └─→ pushEnabled: true → registerPushToken()                │
│              │                                                  │
│              ▼                                                  │
│          expo-notifications로 Expo Push Token 발급               │
│          (디바이스마다 고유한 토큰)                                │
│              │                                                  │
│              ▼                                                  │
│          POST /api/notifications/fcm-token                       │
│          { token: "ExponentPushToken[xxx]", deviceInfo: "ios 18" }│
│              │                                                  │
│              ▼                                                  │
│          AsyncStorage에 토큰 저장 (로그아웃 시 삭제용)            │
│                                                                 │
│  [로그아웃]                                                      │
│      │                                                          │
│      ▼                                                          │
│  unregisterPushToken()                                           │
│      │                                                          │
│      ▼                                                          │
│  DELETE /api/notifications/fcm-token { token: "저장된 토큰" }     │
│      │                                                          │
│      ▼                                                          │
│  AsyncStorage에서 토큰 제거                                      │
│      │                                                          │
│      ▼                                                          │
│  logout() 실행 (auth 토큰 삭제, 쿠키 삭제)                       │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

5. 푸시 알림 딥링크 네비게이션

알림을 탭하면 actionType에 따라 해당 화면으로 이동합니다.

actionType → 화면 매핑

actionType 근로자 고용주
VIEW_WORK_RECORD WorkerHomeMain (주간 캘린더) EmployerHomeMain (일간 캘린더)
VIEW_CORRECTION_REQUEST SentRequests (보낸 요청) EmployerReceivedRequests (받은 요청)
VIEW_PENDING_APPROVAL Notifications EmployerReceivedRequests
VIEW_SALARY WorkerMonthlyCalendar Notifications
VIEW_PAYMENT_MANAGEMENT Notifications RemittanceManage (송금관리)
VIEW_WORKPLACE_INVITATION WorkplaceManage WorkerManage (직원관리)
VIEW_NOTICE Notifications Notifications
NONE Notifications Notifications

딥링크 처리 방식

┌─────────────────────────────────────────────────────────────────┐
│                    딥링크 네비게이션 플로우                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  [앱 종료 상태에서 알림 탭]                                       │
│      │                                                          │
│      ▼                                                          │
│  getLastNotificationResponseAsync()                              │
│  → 마지막 알림 응답 확인 → actionType 추출 → navigate()          │
│                                                                 │
│  [앱 백그라운드에서 알림 탭]                                       │
│      │                                                          │
│      ▼                                                          │
│  addNotificationResponseReceivedListener()                       │
│  → 알림 응답 이벤트 수신 → actionType 추출 → navigate()          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

6. 알림 상세 화면 (NotificationScreen)

┌─────────────────────────────────────────────────────────────────┐
│                    알림 상세 화면 구조                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌───────────────────────────────────────────┐                  │
│  │ Header: [←]  "알림"  [전체 읽음]          │                  │
│  ├───────────────────────────────────────────┤                  │
│  │ Filter Chips                              │                  │
│  │  [전체]  [읽지 않은 알림 N]               │                  │
│  ├───────────────────────────────────────────┤                  │
│  │ NotificationItem (FlatList, pull-refresh) │                  │
│  │  ┌─────────────────────────────────────┐  │                  │
│  │  │ [🔔] 근무 일정이 변경되었습니다.  ×│  │                  │
│  │  │      3분 전                         │  │                  │
│  │  └─────────────────────────────────────┘  │                  │
│  │  ┌─────────────────────────────────────┐  │                  │
│  │  │ [📋] 정정 요청이 승인되었습니다.  ×│  │                  │
│  │  │      1시간 전                       │  │                  │
│  │  └─────────────────────────────────────┘  │                  │
│  ├───────────────────────────────────────────┤                  │
│  │ Pagination (하단 고정)                    │                  │
│  │  < [1] [2] [3] ... [10] >                 │                  │
│  └───────────────────────────────────────────┘                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

서버사이드 페이지네이션

GET /api/notifications?page=0&size=10&is_read=false
→ { content: [...], totalPages: 5, totalElements: 42 }

7. 알림 설정 화면 (NotificationSettingsScreen)

┌─────────────────────────────────────────────────────────────────┐
│                    알림 설정 화면 구조                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌───────────────────────────────────────────┐                  │
│  │ Header: [←]  "알림 설정"                  │                  │
│  ├───────────────────────────────────────────┤                  │
│  │                                           │                  │
│  │  푸시 알림                    [Toggle ●]  │                  │
│  │  앱을 사용하지 않을 때도                   │                  │
│  │  알림을 받습니다.                          │                  │
│  │  ─────────────────────────                │                  │
│  │  디바이스 알림 설정 열기      🔗           │                  │
│  │  ─────────────────────────                │                  │
│  │  디바이스 설정에서 알림 권한을 끄면         │                  │
│  │  푸시 알림이 앱 내 설정과 관계없이          │                  │
│  │  수신되지 않습니다.                         │                  │
│  │                                           │                  │
│  └───────────────────────────────────────────┘                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

토글 동작 (2026-03-09 변경, PR #41)

기존의 AsyncStorage 로컬 저장 방식에서 서버 API 동기화 방식으로 변경됐다.

[화면 진입]
  → GET /api/settings/me → { pushEnabled } 로드 → 토글 초기값 설정

[토글 OFF → ON]:
  → 디바이스 알림 권한 확인
  → 권한 OFF → Alert "디바이스 설정에서 알림을 허용해주세요" + 설정 이동
  → 권한 ON → PUT /api/settings/me { pushEnabled: true }
           → 성공 시 registerPushToken() 호출

[토글 ON → OFF]:
  → PUT /api/settings/me { pushEnabled: false }
  → 성공 시 unregisterPushToken() 호출
구분 이전 (로컬) 현재 (서버)
저장소 AsyncStorage (PUSH_ENABLED_KEY) 서버 DB (/api/settings/me)
다중 디바이스 디바이스별 따로 관리 계정 단위로 통일
훅 연동 useFcmToken가 AsyncStorage 조회 useFcmTokenGET /api/settings/me 조회
관련 파일 src/api/settings/{index,types}.ts 신규 생성

8. API 엔드포인트 요약

인앱 알림

메서드 엔드포인트 설명
GET /api/notifications 알림 목록 조회 (page, size, is_read)
GET /api/notifications/unread-count 읽지 않은 알림 수
GET /api/notifications/stream SSE 실시간 알림 구독
PUT /api/notifications/{id}/read 알림 읽음 처리
PUT /api/notifications/read-all 전체 읽음 처리
DELETE /api/notifications/{id} 알림 삭제

FCM 토큰

메서드 엔드포인트 설명
POST /api/notifications/fcm-token FCM 토큰 등록
DELETE /api/notifications/fcm-token FCM 토큰 삭제

알림 설정 (2026-03-09 신규, PR #41)

메서드 엔드포인트 설명
GET /api/settings/me 사용자 알림 설정 조회 (pushEnabled 등)
PUT /api/settings/me 사용자 알림 설정 갱신

9. 관련 파일

분류 파일 설명
API api/notification/types.ts 알림 타입 정의 (NotificationType, ActionType, PagedResponse 등)
API api/notification/index.ts 알림 API 함수 7개
Store stores/notificationStore.ts unreadCount 전역 상태
Hook hooks/common/useNotifications.ts 알림 화면 데이터 관리
Hook hooks/common/useNotificationStream.ts SSE 구독 + 뱃지 업데이트
Hook hooks/common/useFcmToken.ts 로그인 시 FCM 토큰 자동 등록
Hook hooks/common/useNotificationNavigation.ts 푸시 탭 → 딥링크
Util utils/sse.ts XMLHttpRequest 기반 SSE 클라이언트
Util utils/pushToken.ts 토큰 발급/등록/삭제 유틸
Screen screens/common/NotificationScreen.tsx 알림 상세 화면
Screen screens/common/NotificationSettingsScreen.tsx 알림 설정 화면
Component components/common/notification/NotificationPopup.tsx Header 알림 팝업