docs: 앱 새 메일 알림 · 앱 설정을 계약 · 스킬 · 규칙에 적는다

계약 1절 끝의 옛 메모(/api/push-devices · { minVersion, latestVersion, storeUrl })를 확정한 경로 · 모양 · 규칙으로 바꾸고
(N · 간격 · 따라잡기 · 엔진 after 의 초 경계 · "알림이 멈췄습니다"를 보내는 까닭 표 · 실패 처리 · 실기기로 확인할 것),
"클라이언트 — 앱"에 앱이 실제로 부르는 때를 적었다. 2절 실시간 알림의 붙잡기와 6절 퇴사 마무리 목록도 더했다.
nestjs · docker 스킬과 env · 보안 · 로그 규칙에 FCM 키 자리 · 바깥 연결 · 가릴 값을 더했다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-08 00:51:58 +09:00
parent c0edff10d1
commit b77f95fdff
6 changed files with 146 additions and 7 deletions
+10
View File
@@ -102,6 +102,16 @@
같은 까닭으로 요청 대상의 날 `\`(경로) · `#` · 0x80 이상 바이트는 nginx · 백엔드 모두 400 이다 — Express 는 이런 대상을 옛 `url.parse` 로 다시 읽어 `\` 를 `/` 로 바꿔,
nginx 가 닫은 `/api/internal/` · `/api/health` 가 백엔드에서 열렸다(2026-10-31 리뷰).
### 앱 푸시 (휴대폰 새 메일 알림 — 앱 1단계 · FCM)
- **글은 "새 메일 N통"뿐이다** — 주소 · 이름 · 보낸 사람 · 제목 · 메일 id · 세션 id 는 Google 로 보내지 않는다. 메시지는 한 곳(`modules/push/fcm/fcm-message.ts`)에서 종류 · 개수만 받아 만든다(받는 칸이 없다),
새 메일을 알아채는 쪽도 엔진 연결에서 신호만 받는다. Google 은 기기마다 언제 몇 통이 왔는지는 안다(알려진 한계).
- **휴대폰 주소(FID)는 한 세션에만** — 같은 FID 를 다른 세션이 등록하면 앞 줄을 지운다(같은 휴대폰에서 다른 직원이 로그인해도 앞 직원의 알림이 가지 않게). 직원마다 10개까지.
- **보낼 때 살아 있는 · 제한 없는 앱 세션만 고른다** — 끊은 세션(로그아웃 · 비밀번호 바꾸기 · 운영 도구)은 DB 의 `revoked_at` 으로 바로 빠진다. 등록 경로는 앱 토큰만(웹 쿠키 세션 403 `AUTH_003`).
- **서비스 계정은 알림 전용 하나 + 역할 "Firebase Cloud Messaging API Admin" 하나** — Firebase 의 기본 Admin SDK 계정(Firestore · Auth 까지 쓴다)을 쓰지 않는다. 키는 개발 · 운영 따로,
`backend/.env.{env}` 의 `FCM_SERVICE_ACCOUNT_KEY` 에만 둔다(로그 · 오류 · 응답에 싣지 않는다). 새면 그 키를 Google Cloud 콘솔에서 지우고 새 키로 — 그 키로는 우리 앱 사용자에게 꾸민 알림을 보낼 수 있다(메일은 읽지 못한다).
- 바깥 주소는 상수 두 곳(`oauth2.googleapis.com` · `fcm.googleapis.com`)뿐이다 — 키 파일의 `token_uri` 를 따라가지 않고(다르면 기동하지 않는다) 다른 곳으로 보내는 응답(3xx)도 따라가지 않는다.
## 네트워크 · 인프라
- 보안 헤더(`helmet`) 적용