심층 학습 가이드

웹훅 Web Push 알림 설계

심층 학습 가이드

웹훅 Web Push 알림 설계

외부 자동화 웹훅을 PWA, Service Worker, VAPID 기반 브라우저 푸시와 알림 상세 페이지로 연결하는 실전 설계법

학습 유형

주제 심층 학습

핵심 주제

웹훅 브라우저 푸시 알림

키워드

VIBE 코딩 · Web Push · PWA · Service Worker · 웹훅 · 알림 시스템

학습 개요

이 페이지에서 다루는 것

웹훅 브라우저 푸시 알림

한 번에 끝까지 읽으며 맥락을 쌓을 수 있도록 구성했습니다.

예상 학습 시간

17분

본문과 보조 자료(이미지·영상)를 포함한 대략적인 소요입니다.

학습 팁

섹션 순서대로 읽고, 필요한 부분만 다시 찾아보기

표·이미지·영상은 본문 흐름을 돕는 보조 설명입니다.

웹훅은 외부 시스템이 웹앱에 사건을 알려주는 입구입니다. Web Push는 브라우저가 닫혀 있거나 화면을 보고 있지 않을 때도 운영체제 알림으로 사용자를 깨우는 출구입니다. 두 기술을 연결하면 자동화 엔진, 배포 파이프라인, 모니터링, Hermes 같은 작업자가 중요한 사건을 사람의 휴대폰과 PC 브라우저로 바로 전달할 수 있습니다.

이 글은 한 가지 실전 문제를 다룹니다. '외부 서버에서 작업 완료 웹훅을 보냈을 때, 안드로이드 Chrome과 PC 브라우저에 안정적으로 푸시 알림을 띄우려면 어떤 구조로 설계해야 하는가'입니다. 단순히 알림 코드 몇 줄을 붙이는 이야기가 아닙니다. PWA, Service Worker, Web Push, VAPID, 구독 저장, 웹훅 인증, 만료 구독 정리, Telegram 같은 보조 채널, 클릭 후 상세 페이지 이동까지 하나의 운영 가능한 흐름으로 묶는 방법을 설명합니다.

핵심 결론

웹훅 기반 브라우저 푸시 시스템은 다음 네 줄로 이해하면 됩니다.

  1. 브라우저가 사용자의 허가를 받고 Service Worker와 구독 정보를 만든다.
  2. 서버는 endpoint, p256dh, auth로 구성된 구독 정보를 안전하게 저장한다.
  3. 외부 시스템은 Bearer 토큰이 붙은 웹훅으로 알림 사건을 서버에 보낸다.
  4. 서버는 알림 글을 저장한 뒤 Web Push로 모든 구독 브라우저의 Service Worker에 메시지를 보낸다.

중요한 관점은 '브라우저에 직접 연결한다'가 아닙니다. 서버는 브라우저가 등록한 endpoint로 암호화된 메시지를 보내고, 실제 전달은 Google FCM이나 Mozilla Push Service 같은 브라우저 푸시 서비스가 담당합니다. 브라우저 쪽에서는 Service Worker가 push 이벤트를 받고 showNotification으로 운영체제 알림을 표시합니다.

초보자에게 이 구조는 '웹사이트를 앱처럼 설치하고, 서버가 알림을 보내면 휴대폰 알림창에 뜨게 하는 방법'입니다. 실무자에게는 '외부 자동화 이벤트를 감사 가능한 알림 글과 다중 채널 전송으로 바꾸는 운영 파이프라인'입니다.

왜 중요한가

알림은 기능이 아니라 운영 경로다

배포 완료, 장애 경고, 크론 실패, 결제 이벤트, 백업 완료 같은 사건은 화면을 열어 보기 전까지 기다리면 늦습니다. 특히 혼자 운영하는 서비스나 소규모 팀에서는 별도 모바일 앱을 만드는 비용이 큽니다. Web Push를 쓰면 기존 웹앱 위에 알림 경로를 얹을 수 있습니다.

이 방식의 장점은 세 가지입니다.

장점설명실무 가치
앱 없이 알림PWA와 브라우저 권한만으로 OS 알림을 표시별도 네이티브 앱 개발 비용 감소
사건 기록 보존알림을 DB에 글로 저장놓친 알림도 나중에 상세 페이지에서 확인
채널 분리Telegram, Web Push, 웹 상세 페이지를 독립 처리한 채널 장애가 전체 알림 실패로 번지지 않음

AI 코딩 관점에서는 더 중요합니다. AI 에이전트가 코드를 만들고, 배포하고, 점검하는 자동화가 많아질수록 사람에게 알려야 할 사건도 많아집니다. 이때 무작정 메시지를 뿌리면 스팸이 되고, 너무 조용하면 사고를 놓칩니다. 그래서 인증, Rate Limit, 레벨 분류, 상세 페이지 저장, 만료 구독 정리까지 포함한 설계가 필요합니다.

Web Push는 PWA, Service Worker, VAPID의 조합이다

PWA는 웹앱을 앱처럼 설치하고 실행할 수 있게 만드는 기술 묶음입니다. 홈 화면 아이콘, 매니페스트, 테마 색상, HTTPS, Service Worker가 함께 작동합니다.

Service Worker는 페이지와 별도로 브라우저가 관리하는 백그라운드 JavaScript입니다. 사용자가 해당 탭을 보고 있지 않아도 push 이벤트를 받을 수 있고, 알림 클릭 이벤트도 처리할 수 있습니다.

Web Push는 서버가 브라우저 구독 endpoint에 암호화된 메시지를 보내는 표준입니다. VAPID는 서버 신원을 증명하기 위한 공개키와 비밀키 쌍입니다. 공개키는 브라우저 구독에 쓰이므로 노출되어도 되지만, 비밀키는 서버 밖으로 나가면 안 됩니다.

실제 작업 순서

1단계: 먼저 전체 흐름을 종이에 그린다

구현 전에는 코드보다 데이터 흐름을 먼저 고정합니다.

외부 자동화 엔진이 작업을 끝냅니다. 그 엔진은 웹앱의 notify webhook 엔드포인트로 POST 요청을 보냅니다. 웹앱 서버는 Bearer 토큰을 확인하고, 제목과 본문 길이를 검증하고, 알림 글을 저장합니다. 그다음 Telegram 같은 보조 채널을 선택적으로 호출하고, 저장된 push subscription 목록을 조회해서 Web Push를 발송합니다. 브라우저 푸시 서비스가 메시지를 전달하면 Service Worker가 알림을 띄웁니다. 사용자가 알림을 누르면 알림 상세 페이지가 열립니다.

이 순서를 명확히 해두면 장애 분석도 쉬워집니다. 알림이 안 왔을 때 '웹훅이 안 들어왔는지, 서버 저장은 됐는지, Web Push 전송이 실패했는지, 브라우저 권한이 막혔는지, Service Worker 클릭 처리가 잘못됐는지'를 단계별로 나눌 수 있습니다.

2단계: VAPID 키와 서버 환경을 준비한다

서버는 VAPID 공개키와 비밀키를 가져야 합니다. 공개키는 브라우저가 구독할 때 applicationServerKey로 사용합니다. 비밀키는 서버가 푸시 메시지를 서명할 때 사용합니다.

운영 원칙은 단순합니다.

  • 공개키는 클라이언트가 조회해도 된다.
  • 비밀키는 서버 환경 변수로만 사용한다.
  • 웹훅 인증용 Bearer 토큰은 충분히 긴 랜덤 문자열로 만든다.
  • Telegram 같은 외부 채널 토큰은 서버에서만 사용한다.
  • 저장소에는 실제 비밀값을 절대 넣지 않는다.

여기서 흔한 실수는 '예제니까 괜찮다'며 실제 토큰 모양의 문자열을 문서나 테스트 데이터에 넣는 것입니다. 공개 글과 코드 저장소에는 값이 아니라 역할만 남겨야 합니다. 예를 들어 '웹훅 인증 토큰'이라는 설명은 괜찮지만, 실제 값처럼 보이는 긴 문자열을 남기면 이후 감사와 검색에서 위험 신호가 됩니다.

3단계: 브라우저 구독 등록을 만든다

브라우저에서는 사용자가 직접 알림을 허용해야 합니다. 버튼 클릭 없이 자동으로 권한 팝업을 띄우면 사용자 경험이 나쁘고 브라우저 정책에도 불리합니다. 그래서 '알림 받기' 버튼을 두고, 사용자가 기대를 이해한 상태에서 권한을 요청합니다.

권장 흐름은 다음과 같습니다.

  1. Notification.requestPermission으로 권한을 요청한다.
  2. 사용자가 허용하면 Service Worker를 등록한다.
  3. 서버에서 VAPID 공개키를 가져온다.
  4. pushManager.subscribe로 구독 정보를 만든다.
  5. 구독 정보를 서버의 subscribe 엔드포인트로 보낸다.
  6. 서버는 endpoint를 기준으로 upsert 저장한다.

구독 정보에는 endpoint와 keys.p256dh, keys.auth가 들어갑니다. endpoint는 푸시 서비스로 향하는 고유 URL이고, p256dh와 auth는 payload 암호화에 필요한 키입니다. 이 정보는 비밀번호처럼 사용자 계정 비밀은 아니지만, 알림 발송 권한과 연결되므로 공개 로그에 그대로 남기지 않는 편이 좋습니다.

4단계: 웹훅 수신 API를 알림의 단일 입구로 만든다

웹훅 API는 외부 자동화와 웹앱 사이의 문입니다. 이 문은 편해야 하지만 열려 있으면 안 됩니다.

필수 방어선은 다음과 같습니다.

  • Authorization 헤더의 Bearer 토큰 검증
  • title, body, content의 길이 제한
  • level 같은 값은 info, warn, error, success처럼 허용 목록으로 제한
  • Rate Limit 적용
  • 실패 메시지는 과하게 친절하게 쓰지 않기
  • 알림 글 저장과 채널 발송을 분리하기

좋은 설계에서는 DB 저장이 기준점입니다. 웹훅이 유효하면 먼저 알림 글을 저장합니다. 이후 Telegram 발송이나 Web Push 발송이 실패해도 상세 페이지에는 기록이 남습니다. 반대로 푸시를 먼저 보내고 저장을 나중에 하면, 사용자가 알림을 눌렀을 때 열 페이지가 없거나 장애 분석 기록이 빠질 수 있습니다.

5단계: Web Push 발송은 실패를 정상 시나리오로 다룬다

브라우저 구독은 영구적이지 않습니다. 사용자가 알림 권한을 취소할 수 있고, 브라우저 데이터가 삭제될 수 있으며, 기기를 바꿀 수도 있습니다. 그래서 Web Push 발송 중 404나 410 응답을 받으면 그 구독은 만료 구독으로 보고 DB에서 정리하는 것이 좋습니다.

또한 여러 구독에 발송할 때는 하나의 실패가 전체 실패가 되면 안 됩니다. Promise.allSettled 같은 방식으로 각 구독 결과를 모으고, 성공한 구독이 하나라도 있는지와 제거한 만료 구독 수를 별도로 기록합니다. 이렇게 하면 PC는 실패했지만 안드로이드 폰은 성공한 경우도 정상적으로 표현할 수 있습니다.

6단계: Service Worker에서 push와 notificationclick을 처리한다

Service Worker는 push 이벤트에서 payload를 읽고 showNotification을 호출합니다. 알림 옵션에는 title, body, icon, badge, tag, data.url 같은 값을 넣습니다. tag를 쓰면 같은 종류의 알림을 교체하거나 다시 울리게 할 수 있습니다.

중요한 메서드는 event.waitUntil입니다. Service Worker는 짧게 실행되고 종료될 수 있기 때문에, showNotification 같은 비동기 작업을 waitUntil 안에 넣어야 브라우저가 작업 완료까지 기다립니다.

notificationclick 이벤트에서는 사용자가 알림을 눌렀을 때 이동할 URL을 처리합니다. 이미 같은 도메인의 탭이 열려 있으면 그 탭을 재활용하고, 없으면 새 창을 엽니다. 이 처리가 없으면 사용자는 알림을 눌러도 앱의 맥락으로 들어가지 못하고, 알림은 단순 팝업으로 끝납니다.

7단계: 알림 상세 페이지를 만든다

푸시 알림은 짧아야 합니다. 긴 로그, 원인, 다음 조치, 관련 링크까지 모두 푸시에 담으면 잘리고 읽기 어렵습니다. 그래서 알림의 짧은 body는 푸시와 Telegram에 쓰고, 긴 content는 웹 상세 페이지에 저장하는 구조가 좋습니다.

상세 페이지에는 다음 항목을 담으면 운영 가치가 높아집니다.

  • 제목과 요약
  • 발생 시각
  • source, level
  • 긴 본문 또는 점검 로그
  • 관련 URL
  • 읽음 여부
  • 다음 조치 메모

혼자 쓰는 서비스라면 처음에는 사용자 테이블 없이 push_subscriptions와 notifications 두 테이블만으로도 충분합니다. 나중에 팀원이 늘어나면 사용자별 구독, 채널 선호도, 알림 묶음, 중요도별 조용한 시간 같은 기능을 추가할 수 있습니다.

상황별 예시

예시 1: 배포 완료를 휴대폰과 PC에 동시에 알리기

상황: 자동 배포가 끝나면 외부 배포 스크립트가 웹훅을 호출합니다.

권장 payload는 제목은 짧게, body는 한 줄 요약으로, content에는 상세 로그를 넣는 방식입니다. 예를 들어 제목은 '배포 완료', body는 '프로덕션 배포가 정상 종료되었습니다', content에는 빌드 시간, 대상 환경, 대표 스모크 결과를 적습니다. level은 success로 둡니다.

서버는 이 사건을 notifications에 저장하고, Telegram에는 요약을 보내고, Web Push에는 상세 페이지 URL을 포함해 발송합니다. 사용자는 휴대폰 알림을 눌러 상세 페이지에서 전체 로그를 확인합니다.

예시 2: 모니터링 경고는 소음을 줄여 보내기

상황: CPU 사용률이나 오류율이 잠깐 올라갈 수 있습니다. 모든 순간을 푸시하면 알림 피로가 생깁니다.

이때는 외부 모니터나 웹훅 API 앞단에서 중복 억제 규칙을 둡니다. 같은 source와 level, 같은 tag가 짧은 시간에 반복되면 새 알림을 만들지 않거나 기존 알림을 갱신합니다. Service Worker의 tag 옵션도 함께 쓰면 사용자의 알림창이 같은 경고로 도배되는 일을 줄일 수 있습니다.

실무 기준은 '사용자가 지금 행동해야 하는가'입니다. 즉시 대응이 필요한 장애는 푸시와 Telegram을 모두 켜고, 참고용 통계는 웹 상세 기록만 남기는 식으로 채널을 나눕니다.

예시 3: Hermes 같은 자동화 에이전트의 작업 결과 받기

상황: 에이전트가 새 글을 발행하거나 품질 감사를 끝냈습니다. 모든 로그를 메신저로 보내면 길고 읽기 어렵습니다.

좋은 알림은 세 층으로 나눕니다. 푸시에는 '품질 감사 완료: 주의 2건'처럼 짧은 제목과 요약만 둡니다. Telegram에는 주요 항목 3개 정도를 보냅니다. 상세 페이지에는 검사한 경로, 발견 항목, 다음 조치, 재현 방법을 저장합니다.

이렇게 하면 사람은 알림으로 사건을 인지하고, 자세한 판단은 웹 상세 페이지에서 합니다. AI 에이전트가 장황하게 설명하더라도 사용자 알림창은 짧고 명확하게 유지됩니다.

예시 4: 여러 기기에서 같은 알림 받기

상황: 안드로이드 폰과 PC Chrome에서 모두 알림을 받고 싶습니다.

각 기기에서 한 번씩 사이트에 접속해 알림을 허용하면 됩니다. 서버에는 기기별로 서로 다른 endpoint가 저장됩니다. 웹훅이 들어오면 서버는 모든 구독에 발송하므로 양쪽에 알림이 뜹니다.

주의할 점은 브라우저 권한과 운영체제 알림 설정입니다. 사이트 권한이 허용이어도 Chrome 앱 자체의 알림이 꺼져 있으면 알림이 보이지 않을 수 있습니다. 안드로이드에서는 배터리 최적화 때문에 백그라운드 전달이 지연될 수도 있습니다.

실수와 주의점

권한 요청을 첫 화면에서 바로 띄우는 실수

사용자는 왜 알림을 허용해야 하는지 모른 채 권한 팝업을 보면 거부하기 쉽습니다. 먼저 알림의 이점, 예시, 빈도, 끄는 방법을 설명하고 버튼 클릭 후 요청하세요. 한 번 거부하면 다시 허용시키는 과정이 더 번거롭습니다.

VAPID 비밀키와 웹훅 토큰을 공개 번들에 넣는 실수

브라우저 코드에 들어가는 값은 사용자에게 보인다고 생각해야 합니다. VAPID 공개키는 괜찮지만, VAPID 비밀키와 웹훅 Bearer 토큰은 절대 클라이언트 번들에 들어가면 안 됩니다. 프론트엔드에서 직접 웹훅을 호출하게 만들면 누구나 알림을 발송할 수 있는 구조가 됩니다.

구독 정보를 한 번만 저장하고 갱신하지 않는 실수

구독은 브라우저 상태에 따라 바뀔 수 있습니다. subscribe API는 endpoint 기준 upsert로 만들어 두세요. 같은 endpoint가 다시 오면 키와 updatedAt을 갱신합니다. 오래된 구독은 발송 실패 응답을 보고 정리합니다.

발송 실패를 전체 장애로 보는 실수

구독이 10개 있을 때 1개가 만료되는 것은 흔한 일입니다. 이를 전체 웹훅 실패로 처리하면 운영자가 불필요한 장애 알림을 받습니다. 개별 실패는 기록하되, 성공 수와 실패 수, 제거한 만료 구독 수를 나눠 보고하세요.

Service Worker 업데이트를 가볍게 보는 실수

Service Worker는 일반 JavaScript 파일보다 캐시와 생명주기가 까다롭습니다. 수정 후 즉시 모든 사용자에게 반영되지 않을 수 있습니다. 중요한 알림 로직을 바꿨다면 새 버전 활성화 전략, 캐시 무효화, 브라우저 재등록 테스트를 고려해야 합니다.

테스트 알림을 공개 데이터로 남기는 실수

운영 서비스에서 '테스트입니다' 같은 알림이 공개 목록에 계속 쌓이면 신뢰가 떨어집니다. 테스트 알림은 source를 test로 분리하고, 운영 목록에서 숨기거나 짧은 보존 기간을 두는 것이 좋습니다. 실제 사용자에게 보이는 목록에는 의미 있는 사건만 남겨야 합니다.

검증 체크리스트

구현이 끝났다면 다음 순서로 확인합니다.

서버 검증

  • VAPID 공개키 조회 API가 공개키만 반환하는가
  • subscribe API가 endpoint, p256dh, auth 누락을 거부하는가
  • webhook API가 Bearer 토큰 없이는 거부되는가
  • title, body, content 길이 제한이 적용되는가
  • level 허용 목록이 동작하는가
  • Rate Limit이 과도한 반복 요청을 막는가
  • 알림 글 저장 실패와 채널 발송 실패가 구분되는가
  • Web Push 발송 중 만료 구독이 정리되는가

브라우저 검증

  • HTTPS 환경에서만 알림 활성화 버튼이 노출되는가
  • 권한 거부 시 사용자가 다음 조치를 이해할 수 있는가
  • Service Worker가 등록되는가
  • push 이벤트에서 알림이 표시되는가
  • notificationclick 후 올바른 상세 페이지로 이동하는가
  • 이미 열린 탭이 있으면 새 탭을 남발하지 않는가
  • 안드로이드와 PC에서 각각 구독이 저장되는가

운영 검증

  • 테스트 웹훅 호출 후 notifications에 글이 저장되는가
  • Telegram 실패가 Web Push 성공을 막지 않는가
  • Web Push 실패가 DB 저장을 되돌리지 않는가
  • 알림 상세 페이지에 긴 content가 읽기 좋게 표시되는가
  • 공개 페이지에 내부 토큰, 로컬 경로, 비밀값을 떠올리게 하는 문자열이 없는가
  • 실제 장애 시 롤백이나 재시도 기준이 문서화되어 있는가

다음 단계

처음부터 완벽한 알림 플랫폼을 만들 필요는 없습니다. 1단계는 혼자 쓰는 안정적인 구조입니다. 구독 테이블과 알림 테이블, 웹훅 토큰, Web Push 발송, Service Worker 클릭 이동만 갖추면 충분합니다.

2단계에서는 품질을 높입니다. source별 Rate Limit, level별 채널 선택, 중복 알림 병합, 만료 구독 정리 통계, 테스트 알림 숨김, 상세 페이지 검색을 추가합니다.

3단계에서는 팀 운영으로 확장합니다. 사용자별 구독, 알림 선호도, 조용한 시간, 역할별 수신 범위, 감사 로그, 실패 재시도 큐를 넣을 수 있습니다.

VIBE 코딩에서 가장 좋은 접근은 작게 만들고 끝까지 검증하는 것입니다. 알림 버튼 하나, 구독 저장 하나, 웹훅 하나, Service Worker 하나를 각각 확인한 뒤 연결하세요. 그러면 외부 자동화가 늘어나도 사람에게 필요한 사건만 빠르고 안전하게 전달하는 알림 운영 체계를 만들 수 있습니다.

다음 학습

같은 섹션에서 이어 읽기 좋은 콘텐츠

윤슬 코드·AI 코딩 배포 검증·2026.04.27·9분 읽기

AI 배포 스모크 루프

AI 코딩에서 위험한 순간은 코드가 만들어지는 순간보다 배포 직후입니다. 로컬 테스트와 빌드가 모두 통과해도, 실제 도메인에서는 데이터 연결, 캐시, 라우팅, 브라우저 실행 환경, 공개 문구 같은 이유로 다른 결과가 나올 수 있습니다. 그래서 AI에게 구현을 맡겼다면 배포 후에도 사람이 읽을 수 있는 검증 증거를 남겨야 합니다.

이 글은 한 가지 실전 문제를 다룹니다. 'AI가 만든 변경을 서비스에 올린 뒤 무엇을 확인해야 배포를 끝냈다고 말할 수 있는가'입니다. 답은 거창한 모니터링 체계를 새로 만드는 것이 아니라, 배포 상태, 대표 경로, 콘솔 오류, 공개 금지어, 롤백 기준을 짧고 반복 가능한 라이브 스모크 루프로 묶는 것입니다.

핵심 결론

#AI 코딩#배포 검증#라이브 스모크
요약맥락
윤슬 코드·AI 코드 리뷰와 diff 검토·2026.04.27·15분 읽기

AI diff 리뷰 루프

AI 코딩에서 가장 자주 생기는 착각은 '코드가 만들어졌으니 이제 테스트만 돌리면 된다'는 생각입니다. 하지만 실무에서 중요한 질문은 조금 다릅니다. 이 변경이 왜 필요한가, 어떤 파일이 위험한가, 어떤 회귀를 막았는가, 배포하다 문제가 나면 어디까지 되돌릴 수 있는가를 설명할 수 있어야 합니다.

이 글은 AI 에이전트가 만든 변경을 사람처럼 꼼꼼하게 읽기 위한 diff 리뷰 루프를 다룹니다. 초보자에게 diff는 낯선 화면일 수 있습니다. 쉽게 말하면 diff는 '이번 작업으로 무엇이 바뀌었는지 보여주는 변경 목록'입니다. 숙련자에게 diff는 배포 위험을 가장 빨리 발견하는 지도입니다. AI가 코드를 빠르게 만들수록, diff를 기준으로 검토하는 습관이 더 중요해집니다.

핵심 결론

#AI 코딩#코드 리뷰#diff
요약맥락