개발 공부중

[사이드 프로젝트 회고 #2] 푸시 기능을 앱 대신 FCM(Firebase Cloud Messaging)으로 해결하기 본문

카테고리 없음

[사이드 프로젝트 회고 #2] 푸시 기능을 앱 대신 FCM(Firebase Cloud Messaging)으로 해결하기

개발자 leelee 2026. 7. 5. 16:15

 

1편에서 닷홈빌더의 한계 때문에 PHP로 새로 사이트를 만들기로 했다. 사이트를 다 완성하고 알림 기능을 추가하기 전에 그다음 고민으로 "이걸 어떤 방식으로 구현할까" 생각해봤다.

알림이 필요하면, 앱을 만들어야 하는 거 아닌가?

새 글 알림, 댓글 알림 기능이 필요하다는 결론을 내리고 나서, 가장 먼저 떠오른 방법은 사실 "앱으로 만들기"였다. 푸시 알림이라는 게 원래 앱에서 흔히 쓰는 기능이라, "그냥 앱 하나 만들면 되지 않을까"라는 생각이 자연스럽게 들었다.

근데 생각해볼수록 앱으로 가는 건 이 프로젝트의 규모와 전혀 맞지 않았다.

  • 안드로이드/iOS 각각 개발해야 하거나, 최소한 크로스플랫폼 프레임워크를 새로 익혀야 한다
  • 앱스토어/플레이스토어 등록 절차와 심사를 거쳐야 한다
  • 이미 PHP로 만든 웹사이트가 있는데, 그걸 앱으로 다시 만드는 건 중복 작업이다

이용자가 적은 익명 글쓰기 사이트 하나에 알림 기능을 붙이려고 앱까지 새로 만드는 건, 배보다 배꼽이 큰 선택이었다.

차라리 네이버 카페 기능을 쓰는게 나을 정도...

아이폰의 "홈 화면에 추가" 기능이 힌트가 됐다

찾아보니 아이폰의 홈 화면에 추가 기능으로 웹사이트를 어플처럼 이용할 수 있었다. 사파리에서 웹사이트를 열고 "홈 화면에 추가"를 누르면, 그 사이트가 마치 하나의 앱처럼 아이콘으로 홈 화면에 생긴다. 이 상태로 열면 브라우저 주소창도 사라지고, 진짜 앱을 켠 것 같은 느낌을 준다. 

 

이렇게 홈 화면에 추가한 상태에서도, 푸시 알림을 받을 수 있을까?

FCM (Firebase Cloud Messaging)

이 질문에 대한 답을 찾다가 Firebase Cloud Messaging(FCM)을 알게 됐다. FCM은 원래 안드로이드/iOS 앱을 위한 푸시 서비스로 많이 알려져 있지만, 웹 푸시(Web Push) 도 지원한다. 그리고 확인해보니 이 웹 푸시가 홈 화면에 추가한 PWA(Progressive Web App) 상태에서도 정상적으로 동작한다는 걸 확인했다.

정리하면 이렇게 방향이 잡혔다.

  • 앱을 새로 만드는 대신, 기존 PHP 웹사이트를 그대로 유지한다
  • 아이폰/안드로이드 사용자는 "홈 화면에 추가"로 앱처럼 쓰게 한다
  • 알림은 FCM 웹 푸시로 처리해서, PC 브라우저와 홈 화면에 추가된 모바일 상태 모두에서 받을 수 있게 한다

이 방향이면 앱스토어 심사도, 별도 앱 개발 비용도 없이 "새 글이 올라오면 알려주는 앱 같은 사이트"를 만들 수 있었다.

 

좌 온라인 / 우 모바일

 

푸시 알림 구조

방향을 정하고 나서 실제로 붙인 흐름을 정리하면 이렇다.

사용자
   │
   ▼
'새 글 알림 받기' 버튼 클릭
   │
   ▼
Notification API 권한 요청
   │
   ▼
FCM getToken()
   │
   ▼
fcm_tokens 테이블 저장
   │
   ▼
게시글 작성
   │
   ▼
send_new_post_notification()
   │
   ▼
send_notification()
   │
   ├── notifications 테이블 저장
   │
   └── fcm_tokens 조회
            │
            ▼
     사용자의 모든 토큰 조회
            │
            ▼
     fcm_send_to_token()
            │
            ▼
 Firebase HTTP v1 API
            │
            ▼
      PC / 모바일 푸시

 

 

이걸 크게 세 단계로 나눠보면 이렇다.

1. 프론트에서 알림 권한을 요청하고 토큰을 발급받는다.

async function requestNotificationPermission() {
  const permission = await Notification.requestPermission();

  if (permission === "granted") {
    const token = await messaging.getToken({
      vapidKey: "발급받은_VAPID_KEY"
    });

    // 발급받은 토큰을 서버로 전송해서 저장
    fetch("save_token.php", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ token })
    });
  }
}

 

2. 게시글이 등록되면 구독자를 먼저 조회한다. 게시글이 등록됐다고 모든 사용자에게 알림을 보내는 건 아니었다. 게시판을 구독한 사용자만 조회하도록 구현했다. 실제로는 send_new_post_notification()에서 먼저 구독자를 가져온다.

$stmt = $pdo->prepare("
    SELECT user_id
    FROM board_subscriptions
    WHERE board_type = :type
      AND user_id != :writer_id
");

$stmt->execute([
    ':type' => $board_type,
    ':writer_id' => $writer_id
]);

$subscribers = $stmt->fetchAll(PDO::FETCH_COLUMN);

작성자는 제외하고, 구독한 회원에게만 알림을 보내도록 했다.

 

3. send_notification() 하나에서 모든 알림을 처리하도록 만들었다.

처음에는 게시글 알림, 댓글 알림, 답글 알림마다 각각 FCM을 호출하려고 했다. 그런데 같은 코드가 계속 반복됐다. 그래서 알림 저장 + 푸시 발송을 모두 처리하는 send_notification() 함수를 하나 만들었다. 이 함수는 다음 세 가지를 모두 담당한다.

  1. notifications 테이블 저장
  2. 사용자의 FCM 토큰 조회
  3. 모든 토큰으로 푸시 발송

4. 먼저 사이트 알림을 저장한다.

푸시만 보내면 사용자가 알림을 놓쳤을 때 확인할 방법이 없다. 그래서 가장 먼저 notifications 테이블에 저장하도록 만들었다.

INSERT INTO notifications
(
    user_id,
    type,
    target_id,
    message,
    url
)

이렇게 저장해두면

  • 사이트 안에서도 알림 목록을 볼 수 있고
  • 읽음 처리도 가능하며
  • 삭제도 할 수 있다.

5. 저장된 모든 토큰으로 푸시를 보낸다. 그다음이 FCM이다.

$stmt = $pdo->prepare("
    SELECT token
    FROM fcm_tokens
    WHERE user_id = :uid
");

$stmt->execute([
    ':uid' => $to_user_id
]);

$tokens = $stmt->fetchAll(PDO::FETCH_COLUMN);

foreach ($tokens as $token) {
    fcm_send_to_token(
        $token,
        $title,
        $message,
        $url
    );
}

여기서 fetchAll()을 쓴 이유는, 한 사용자가 PC와 모바일 두 곳 모두 로그인한 경우 두 기기로 모두 알림을 보내기 위해서였다.

 

6. 실제 유저가 푸시 알람을 설정하는 방법

상단 🔔 클릭 후 푸시 켜기 버튼을 누르면
댓글, 답글, 새 글 알림(+개별페이지에서 클릭 필수)을 받을 수 있습니다.

아이폰은 Safari에서 사이트 접속 후
공유 버튼 → 홈 화면에 추가 → 홈 아이콘으로 실행해야 푸시 알림이 작동합니다.

갤럭시는 Chrome 브라우저에서
푸시 켜기 버튼을 누르면 바로 사용할 수 있습니다.

 

 

7. 그런데 이 구조 때문에 버그도 발생했다.

이 방식은 여러 기기를 쓰는 사용자에게는 편리했지만, 개발하면서 테스트를 반복하다 보니 문제가 생겼다. 처음엔 같은 계정으로 PC에서 '새 글 알림 받기' 버튼을 눌러 토큰을 저장했다. 이후 모바일에서도 같은 계정으로 알림을 허용했다. 그런데 개발 과정에서 기존 PC 토큰이 정리되지 않은 채 fcm_tokens 테이블에 그대로 남아 있었다.

당장은 두 기기 모두에 알림이 잘 가는 것처럼 보였지만, 초기화가 제대로 안 된 토큰들이 결국 "알림이 중복으로 오는 버그"로 나타났다.

이 선택이 이후 구현에 준 영향

이 결정은 이후 알림 기능을 구현하는 방식 전체에 영향을 줬다. 앱 하나만 있었다면 "이 사용자에게 보낸다"는 개념으로 끝났을 텐데, "웹사이트 + PWA + FCM" 조합에서는 한 사용자가 여러 토큰(기기)을 가질 수 있다는 걸 구조적으로 감당해야 했다. 바로 위에서 언급한 PC 토큰이 정리되지 않고 남아있던 문제도 결국 이 구조 때문에 생긴 일이었다. 

돌아보며

앱을 만들지 않기로 한 선택으로 배포·심사·업데이트 같은 앱 특유의 운영 부담 없이 빠르게 기능을 붙이고 고칠 수 있었다.

개인이 혼자 운영하는 사이드 프로젝트에는 이 쪽이 훨씬 현실적인 선택이었다고 생각한다.

Comments