72시간 활성화 넛지 · 자료실 넛지 · 일본 바이어 넛지 · 언어별 발송 · 발송율 페이싱
id/zh/th 사용자는 모국어 메일 누락(영어 폴백).| QA #19 기대 | 실제 코드 | 평가 |
|---|---|---|
| "발송 0건 체험(trial) 계정"에 72h 넛지 | 조건 = noBuyerSearchDays:3(바이어검색 0건). trial 한정 아님, "발송 0건"도 아님 |
조건 불일치 바이어검색만 안 한 유료·발송이력 계정도 대상 가능 |
| 자료실·일본바이어 넛지 전 로케일 정상발송 | 자료실 6개 입력 → ko/ja/en 3개만, id/zh-CN/th → 영어. 자동넛지 zh/th 템플릿 없음 → ko 폴백 | 모국어 누락 발송 자체는 됨 |
| 발송율 페이싱으로 부분발송 사고 없음 | 자동넛지=순차 for(페이싱 없음), 자료실=건당 1통. 페이싱 코드(14통/s)는 release-note 전용 |
페이싱 부재 SES adaptive 재시도에만 의존 |
bounds(): 윈도우 폭 delay + 2h, 워커는 55분 주기(auto-nudge.worker.ts:41). 직접 검산:
now=10:00 → [−74h, −72h], now=10:55 → 둘째 from = 10:00−72h−65min < 첫째 to = 10:00−72h → 65분 오버랩followup_emails unique로 차단).| 심각도 | 위치 | 내용 |
|---|---|---|
| MED | release-note-nudge.service.ts:36 | 페이싱 14통/s가 단일 인스턴스 가정. SES 25/s를 시퀀스·OTP·자동넛지와 공유 → 여러 발송원 동시 가동 시 합산 초과 → throttle. 시퀀스 워커의 throttleRedis 같은 전역 throttle 부재 |
| MED | release-note-nudge.service.ts:432 | partial 시 실패 수신자 목록 미저장(failedCount 숫자만) → 재발송 시 전체 재발송=중복 위험. 자동 재시도 없음 |
| MED | auto-nudge.service.ts:620-653 | SES 성공 후 DB insert 실패 시 failed++ 처리되나 메일은 이미 발송 → 통계 부정확 + (unique 덕에) 재발송 차단되어 영구 누락 |
| MED | auto-nudge.service.ts:302 | trialOnly 쿼리는 정상이나 시드에 이 조건을 쓰는 넛지가 없음 → 명세갭 ①의 원인 |
| LOW | auto-nudge.service.ts:89-121 | 모든 언어 템플릿 null이면 warn만 찍고 silent skip. seed엔 ko 있어 실제 발송은 되나 템플릿 관리 실수 시 침묵 누락 |
verifySharedSecret timingSafeEqual 적용 — 타이밍 공격 방어 (resource-nudge-email.routes.ts:57)escapeHtml로 name/downloadUrl/resourceTitle 모두 이스케이프 — XSS 방어followup_emails unique constraint 기반 중복방지 + 단계별 early-returnretryMode:"adaptive", maxAttempts:5 — 일시적 throttle 흡수런타임 크래시·치명 버그는 없음. "잘 구현"은 맞되, QA #19 명세와 코드 사이 정의 불일치(조건·페이싱·언어 커버리지)가 진짜 문제.