관리페이지 데이터 전송 구현
Deploy EG-BIM QA Gateway / deploy (push) Successful in 2m4s

This commit is contained in:
root
2026-09-21 14:46:36 +09:00
parent 42516b4f8b
commit 3c10478482
54 changed files with 16055 additions and 45 deletions
@@ -0,0 +1,429 @@
# ABC Webhook–네이버웍스 알림 연동 작업 계획
- 작성일: 2026-08-26
- 목적: ABC UserFeedback에서 발생한 피드백 이벤트를 웹훅으로 수신하고, 네이버웍스 Bot API를 통해 관리자에게 알림을 보낸다.
- 1차 범위: 신규 피드백 등록, 피드백 상태 변경, 관리자 공개 댓글 등록
- 현재 상태: 핵심 구현 완료, 로컬 검증 완료. 네이버웍스 실발송과 ABC 외부 Webhook 실연동은 자격증명·운영 설정 후 검증 필요
## 1. 목표 시나리오
```text
ABC UserFeedback
-> ABC Webhook 이벤트 발송
-> 우리 백엔드 웹훅 수신 API
-> 서명·토큰 검증 및 중복 요청 검사
-> 이벤트 표준화
-> 알림 대상자·메시지 결정
-> 네이버웍스 Bot API 호출
-> 발송 결과와 실패 이력 저장
```
### 1.1 1차 이벤트
| 이벤트 | 알림 제목 | 기본 수신 대상 |
| --------------------- | ---------------- | --------------------------------------------- |
| 신규 피드백 등록 | 신규 피드백 등록 | 피드백 담당자, 프로젝트 관리자, 피드백 작성자 |
| 피드백 상태 변경 | 피드백 상태 변경 | 피드백 담당자, 프로젝트 관리자, 피드백 작성자 |
| 관리자 공개 댓글 등록 | 관리자 댓글 등록 | 해당 피드백 작성자만 |
내부 메모는 일반 댓글과 공개 범위가 다르므로 1차 범위에서는 알림 대상에서 제외한다. 내부 메모를 네이버웍스로 보내려면 관리자 전용 수신 정책을 별도로 확정해야 한다.
## 2. 현재 구조 확인 사항
- [x] NestJS API에 프로젝트별 Webhook 등록·조회·수정·삭제 API가 존재함
- [x] Webhook에 이벤트 종류와 프로젝트·채널 범위를 설정하는 구조가 존재함
- [x] 실제 피드백 등록·상태 변경·관리자 공개 댓글 등록 이벤트를 내부 알림 흐름에 연결
- [x] 외부 Webhook 수신 전용 라우터 구현
- [ ] 현재 Webhook payload 형식과 이벤트별 예시 확보
- [x] Webhook 인증 방식(서명 또는 토큰) 구현
- [x] 네이버웍스 Bot API 인증·발송 어댑터 구현
현재 Webhook 관리 API가 있다는 것만으로는 이벤트 발송과 네이버웍스 전송이 완성된 상태가 아니다. 발송 지점과 payload 계약을 먼저 확인한 뒤 수신 API를 연결한다.
## 3. 권장 구현 구조
### 3.1 웹훅 수신 계층
추후 이벤트가 늘어나도 라우터를 변경하지 않도록 단일 수신 엔드포인트에서 처리한다.
권장 경로 예시:
POST /api/integrations/abc/webhooks
수신 처리 순서:
1. 원문 body와 인증 헤더를 확보한다.
2. Webhook 토큰 또는 서명을 검증한다.
3. `eventId` 또는 payload hash로 중복 요청을 검사한다.
4. 이벤트 타입을 허용 목록과 비교한다.
5. 이벤트별 payload를 내부 표준 이벤트로 변환한다.
6. 빠르게 `2xx` 응답을 반환하고 알림 발송을 처리한다.
7. 발송 결과를 로그에 기록하고 실패 시 재시도 대상으로 남긴다.
인증에 실패한 요청은 상세 payload를 로그에 남기지 않고 `401` 또는 `403`으로 응답한다. 이벤트 처리 실패와 네이버웍스 일시 장애는 Webhook 자체 인증 실패와 구분한다.
### 3.2 표준 이벤트 모델
외부 ABC payload에 직접 의존하지 않고 다음과 같은 내부 모델로 변환한다.
```ts
type NotificationEventType =
| 'feedback.created'
| 'feedback.status_changed'
| 'feedback.admin_comment_created';
interface NotificationEvent {
eventId: string;
type: NotificationEventType;
occurredAt: string;
projectId: number;
channelId: number;
feedbackId: number;
title?: string;
feedbackUrl?: string;
actor?: {
id?: string;
name?: string;
email?: string;
};
status?: {
previous?: string;
current: string;
};
comment?: {
id?: number;
content: string;
isInternal: boolean;
};
}
```
이벤트 변환기와 메시지 템플릿을 분리해 ABC payload가 변경되거나 이벤트가 추가되어도 네이버웍스 클라이언트는 수정하지 않도록 한다.
### 3.3 네이버웍스 연동 계층
다음 인터페이스를 기준으로 네이버웍스 구현체를 분리한다.
```ts
interface NotificationSender {
send(message: NotificationMessage): Promise<NotificationSendResult>;
}
```
권장 구성:
- `WebhookReceiver`: ABC Webhook 검증·수신
- `NotificationEventMapper`: 외부 payload를 표준 이벤트로 변환
- `NotificationRouter`: 이벤트별 수신자 결정
- `NaverWorksClient`: 인증 토큰 발급·갱신 및 메시지 API 호출
- `NaverWorksMessageBuilder`: 이벤트별 메시지 조합
- `NotificationLogService`: 요청·성공·실패·재시도 이력 기록
현재 라우팅 구현은 SSO/ABC 피드백 데이터의 이메일을 NAVER WORKS 로그인 ID로 사용한다. 신규 피드백과 상태 변경은 `assignee_email`, Secretary DB에서 프로젝트·채널 매핑으로 조회한 `PROJECT_MANAGER`, ABC 프로젝트 멤버의 관리자 이메일, `requester_email`을 합친 뒤 대소문자 기준으로 중복 제거한다. 관리자 공개 댓글은 `requester_email`만 대상으로 한다. 사용자별 발송은 `/bots/{botId}/users/{userId}/messages`를 사용하고 기본 방 발송으로 대체하지 않는다. 프로젝트 관리자 지정의 원본은 Secretary DB이며, ABC API는 `x-api-key`로 보호된 내부 수신자 조회 API를 통해서만 이를 읽는다.
## 4. 필요한 환경변수
실제 변수명은 기존 환경변수 규칙에 맞춰 확정한다. 비밀값은 코드, `.env.example`, README, 채팅에 입력하지 않는다.
### 4.1 ABC Webhook 수신
```dotenv
ABC_WEBHOOK_ENABLED=false
ABC_WEBHOOK_PATH=/api/integrations/abc/webhooks
ABC_WEBHOOK_TOKEN=
ABC_WEBHOOK_SIGNING_SECRET=
ABC_WEBHOOK_ALLOWED_PROJECT_IDS=
SUPPORT_API_BASE_URL=http://127.0.0.1:8010
MASTER_API_KEY=
```
`TOKEN` 방식과 서명 방식 중 ABC가 실제로 제공하는 인증 방법만 활성화한다. 둘 다 지원할 경우 운영에서는 서명 검증을 우선한다.
### 4.2 네이버웍스 Bot API
```dotenv
NAVER_WORKS_ENABLED=false
NAVER_WORKS_API_BASE_URL=
NAVER_WORKS_AUTH_URL=
NAVER_WORKS_BOT_ID=
NAVER_WORKS_DOMAIN_ID=
NAVER_WORKS_CLIENT_ID=
NAVER_WORKS_CLIENT_SECRET=
NAVER_WORKS_SERVICE_ACCOUNT=
NAVER_WORKS_PRIVATE_KEY=
NAVER_WORKS_DEFAULT_ROOM_ID=
NAVER_WORKS_DEFAULT_USER_ID=
```
필요한 값은 네이버웍스 인증 방식에 따라 달라질 수 있다. 특히 `client secret`, 서비스 계정, 개인키는 Gitea Secrets 또는 스테이징 서버의 비밀 환경변수로만 등록한다.
### 4.3 알림 처리 정책
```dotenv
NOTIFICATION_DELIVERY_MODE=async
NOTIFICATION_MAX_RETRIES=3
NOTIFICATION_RETRY_BASE_DELAY_MS=1000
NOTIFICATION_LOG_ENABLED=true
NOTIFICATION_INCLUDE_FEEDBACK_URL=true
NOTIFICATION_MAX_BODY_LENGTH=10000
NOTIFICATION_RATE_LIMIT_PER_MINUTE=60
NOTIFICATION_CIRCUIT_BREAKER_FAILURES=5
NOTIFICATION_KILL_SWITCH=false
```
## 5. 알림 정책
### 5.1 수신 대상
확정된 1차 수신 정책은 다음과 같다.
| 이벤트 | 수신 대상 | 발송 기준 |
| --------------------- | --------------------------------------------- | ------------------------------------------------ |
| 신규 피드백 등록 | 피드백 담당자, 프로젝트 관리자, 피드백 작성자 | 동일 사용자가 여러 역할에 해당하면 한 번만 발송 |
| 피드백 상태 변경 | 피드백 담당자, 프로젝트 관리자, 피드백 작성자 | 실제 상태가 변경된 경우에만 발송 |
| 관리자 공개 댓글 등록 | 해당 피드백 작성자 | 담당자·프로젝트 관리자·기본 방에는 발송하지 않음 |
- 피드백 담당자와 프로젝트 관리자는 해당 프로젝트·채널 범위에 한정한다.
- 피드백 작성자는 SSO 사용자와 네이버웍스 계정 매핑이 확인된 경우에만 발송한다.
- 동일 사용자가 담당자·프로젝트 관리자·작성자 역할을 여러 개 가지고 있어도 중복 발송하지 않는다.
- 담당자 또는 프로젝트 관리자가 지정되지 않은 경우 해당 역할로는 발송하지 않는다.
- 작성자 계정 매핑에 실패한 경우 임의의 사용자나 전체 방으로 대체 발송하지 않고 실패 이력으로 남긴다.
- 비밀글의 사용자 알림에는 제목·본문·댓글 내용을 포함하지 않고, 권한 검증이 가능한 상세 링크와 최소 정보만 사용한다.
### 5.2 이벤트 조건
- 실제 상태가 변경된 경우에만 발송할지
- 상태를 같은 값으로 다시 저장할 때는 발송하지 않을지
- 관리자 공개 댓글만 발송하고 내부 메모는 제외할지
- 댓글 수정·삭제도 알림을 보낼지
- 이슈 상태 변경과 Gitea 이벤트를 1차 범위에 포함할지
### 5.3 메시지 정책
기본 메시지에는 다음 정보를 포함하는 것을 권장한다.
- 프로젝트명·채널명
- 피드백 ID
- 피드백 제목
- 변경 전·후 상태
- 댓글 작성자와 댓글 내용 일부
- 피드백 상세 페이지 링크
비밀글은 네이버웍스 메시지에 본문을 포함하지 않고, 권한이 있는 사용자가 상세 페이지에서 확인하도록 한다. 댓글은 개인정보와 긴 본문 노출을 막기 위해 길이 제한과 마스킹 정책을 둔다.
### 5.4 비정상 Webhook 차단 정책
Webhook은 인터넷에 노출될 수 있는 입력 경계로 취급한다. 아래 조건을 만족하지 않는 요청은 이벤트 처리와 네이버웍스 발송을 진행하지 않는다.
| 상황 | 처리 방법 | 목적 |
| --------------------------------------- | ------------------------------------------------ | ------------------------------ |
| 인증 토큰·서명 없음 | `401/403` 응답, payload 미기록 | 위조 요청 차단 |
| 서명 불일치 | `401/403` 응답, 보안 이벤트만 기록 | payload 변조 차단 |
| 서명 timestamp가 허용 시간 초과 | 거부 | 캡처 payload 재전송 차단 |
| 지원하지 않는 `eventType` | 인증 후 `202`로 무시하고 이벤트 타입만 기록 | 불필요한 재시도·오류 폭주 방지 |
| 필수 식별자 누락 | `400`, 알림 미발송 | 잘못된 대상 발송 방지 |
| 존재하지 않는 프로젝트·채널·피드백 | 검증 후 무시 또는 격리 | 삭제·오래된 데이터 오발송 방지 |
| 허용 목록 밖의 프로젝트 | 무시, 보안 로그 기록 | 다른 프로젝트 데이터 유출 방지 |
| 허용 목록 밖의 수신자 | 발송하지 않고 격리 | 관리자 외 대상 오발송 방지 |
| 너무 큰 body 또는 잘못된 Content-Type | `413/415` | 리소스 고갈·파싱 공격 방지 |
| 같은 이벤트 재수신 | idempotency key로 한 번만 발송 | 중복 메시지 방지 |
| 오래된 이벤트 또는 순서가 뒤바뀐 이벤트 | event version 검증 후 무시 또는 최신 상태 재조회 | 과거 상태로 되돌아간 알림 방지 |
인증 실패 요청에는 원문 body, 댓글 내용, 이메일, IP/MAC 등의 개인정보를 로그로 남기지 않는다. 반복적인 인증 실패는 IP·경로 단위 rate limit 또는 차단 대상으로 분류한다.
### 5.5 이벤트 유효성 및 중복 처리
- 이벤트 식별자는 ABC가 제공하는 `eventId`를 우선 사용하고, 없으면 `payload hash + occurredAt` 조합으로 생성한다.
- 중복 기준은 `eventId + notification target + template version`으로 한다. 수신자별 발송이 필요한 경우 한 이벤트를 대상자마다 한 번만 처리한다.
- 상태 변경은 `previousStatus``currentStatus`가 같으면 알림을 보내지 않는다.
- 이벤트가 현재 ABC 데이터와 일치하지 않으면 payload만 믿지 않고 피드백 상세를 재조회한다.
- 이미 더 최신 상태가 처리된 경우 오래된 이벤트는 폐기한다.
- 댓글 이벤트는 댓글 ID를 기준으로 중복 처리하며, 수정·삭제 이벤트는 별도 허용 목록에 추가하기 전까지 무시한다.
- Webhook 수신 성공과 네이버웍스 발송 성공은 별도 상태로 기록한다. 수신 성공을 발송 성공으로 간주하지 않는다.
### 5.6 수신자 및 권한 안전장치
- 수신자는 이벤트 payload가 지정한 임의의 주소를 그대로 사용하지 않고, 프로젝트·채널·담당자 정보를 기준으로 서버에서 결정한다.
- 네이버웍스 방 ID와 사용자 ID는 프로젝트별 allowlist에 등록된 값만 사용한다.
- 담당자 정보가 없거나 비활성 사용자인 경우 전체 관리자 방으로 자동 전송하지 않는다. 별도 격리 대상 또는 명시된 기본 운영자에게만 보낸다.
- 작성자에게 알림을 보낼 때는 SSO 계정과 네이버웍스 계정의 매핑이 확인된 경우에만 발송한다.
- 비밀글의 제목·본문·댓글 내용은 사용자용 방에 포함하지 않는다. 필요한 경우 관리자 전용 방에 최소 정보만 보낸다.
- 내부 메모는 공개 댓글과 다른 이벤트로 취급하고, 관리자 전용 정책이 확정되기 전까지 외부 알림을 금지한다.
- 프로젝트별 환경과 수신자 설정을 분리해 다른 프로젝트의 알림 방으로 섞이지 않도록 한다.
### 5.7 재시도·장애·폭주 제어
- 재시도 대상은 네트워크 오류, timeout, `408`, `429`, `5xx`로 제한한다.
- `400`, `403`, 잘못된 수신자 등 영구 오류는 재시도하지 않고 실패 이력과 원인을 저장한다.
- `401`은 토큰을 한 번 갱신한 뒤 한 차례만 재요청한다. 반복 인증 실패는 즉시 중단한다.
- 지수 backoff와 jitter를 사용하고, 최대 재시도 횟수를 넘으면 격리 큐 또는 재처리 목록에 저장한다.
- 네이버웍스 장애가 지속되면 circuit breaker를 열어 즉시 실패시키고, ABC Webhook 수신 자체는 정상적으로 종료한다.
- 짧은 시간에 이벤트가 급증하면 사용자별·프로젝트별·전체 발송량 제한을 적용한다.
- 동일 피드백의 연속 상태 변경은 짧은 시간 동안 묶음 알림 또는 마지막 상태 알림으로 축약할 수 있다. 단, 이 정책은 업무상 누락이 허용되는지 확인한 뒤 적용한다.
- 실패한 발송을 무한 재시도하지 않으며, 관리자에게 재처리 필요 건수만 별도로 알린다.
### 5.8 무한 루프 및 자기 자신이 만든 이벤트 차단
- 네이버웍스 발송 결과나 Bot이 남긴 메시지가 ABC 피드백 이벤트로 되돌아오는 구조인지 확인한다.
- 이벤트 actor가 연동용 Bot 또는 시스템 계정이면 관리자 댓글 알림 대상에서 제외한다.
- 발신 Webhook과 수신 Webhook URL이 동일하거나 서로 재호출하는 구성이 되지 않도록 배포 시 검사한다.
- 알림 메시지에 포함된 링크 조회는 이벤트를 다시 생성하지 않는 읽기 전용 경로를 사용한다.
- 연동별 `source``correlationId`를 기록해 동일 연동에서 발생한 재귀 호출을 탐지한다.
### 5.9 개인정보·로그·운영 안전
- 네이버웍스 메시지에는 업무 처리에 필요한 최소 정보만 포함한다.
- 이메일, 전화번호, IP, MAC 주소, SSO 토큰, Webhook 원문 인증값은 메시지와 일반 로그에서 제외한다.
- 댓글 본문은 최대 길이를 제한하고 HTML·스크립트·제어문자를 제거한 평문으로 변환한다.
- 로그에는 `eventId`, 프로젝트 ID, 피드백 ID, 처리 상태, 실패 코드, correlation ID만 기본 저장한다.
- access token, client secret, private key, Webhook secret은 로그·에러 응답·Swagger 예시에 절대 포함하지 않는다.
- 스테이징 Bot·방과 운영 Bot·방의 자격증명 및 수신자 allowlist를 분리한다.
- 긴급 상황에서 신규 발송만 중지할 수 있는 `NOTIFICATION_KILL_SWITCH`를 제공하고, 수신 이벤트와 실패 이력은 보존한다.
- 설정 변경과 kill switch 활성화·해제 이력은 관리자 감사 로그에 남긴다.
### 5.10 ACK 및 오류 응답 정책
Webhook 제공자가 재전송하는 조건을 고려해 응답을 다음과 같이 고정한다.
| 조건 | 응답 | 후속 처리 |
| ----------------------- | --------: | ---------------------------------- |
| 인증 실패 | `401/403` | 처리하지 않음 |
| body 형식 오류 | `400` | 처리하지 않음 |
| 허용되지 않은 이벤트 | `202` | 무시 이력만 저장 |
| 인증된 신규 이벤트 접수 | `202` | 비동기 발송 |
| 중복 이벤트 | `200/202` | 기존 결과 재사용, 재발송하지 않음 |
| 내부 큐 저장 실패 | `503` | 제공자 재전송 유도, 장애 로그 저장 |
네이버웍스 발송이 실패했다는 이유로 이미 수신한 Webhook을 무조건 `5xx`로 응답하지 않는다. 그렇지 않으면 ABC가 같은 이벤트를 반복 전송하여 중복 알림이 발생할 수 있다.
## 6. 구현 전 확정 항목
다음 항목은 구현 전에 업무 담당자와 확정한다.
- [x] 신규 피드백·상태 변경·댓글별 최종 수신 대상
- 담당자 미지정·계정 매핑 실패·프로젝트 설정 누락 시의 격리 대상
- 피드백 상태 변경과 이슈 상태 변경을 같은 알림으로 묶을지 여부
- 비밀글·내부 메모의 네이버웍스 전송 허용 범위
- 상태가 짧은 시간에 여러 번 바뀔 때 즉시 발송할지 묶음 발송할지
- 댓글 본문 최대 길이와 개인정보 마스킹 규칙
- 실패 알림을 네이버웍스 외 별도 채널로 보낼지 여부
- 발송 로그 보관 기간과 재처리 권한
- 스테이징과 운영의 Bot, 방, 수신자, Secret 분리 방식
## 7. 작업 단계
### Phase 1. 연동 계약 확인
- [x] ABC Webhook 이벤트 타입과 내부 이벤트 이름 추가
- [ ] 신규 등록·상태 변경·댓글 등록 payload 샘플 확보
- [x] Webhook 수신 인증 방식 구현: HMAC 서명 우선, 토큰 방식 지원
- [x] 네이버웍스 Bot API 인증 방식과 메시지 API 확인
- [ ] 관리자 방 또는 사용자별 수신자 식별자 확보
- [ ] 스테이징용 네이버웍스 Bot과 테스트 방 지정
### Phase 2. 웹훅 수신 API
- [x] Webhook 수신 DTO와 이벤트 허용 목록 작성
- [x] 토큰·서명 검증 구현
- [x] timestamp·body size·Content-Type 기본 검증 구현
- [x] 프로젝트 allowlist 검증 구현
- [x] 요청 ID와 중복 이벤트 방지 구현
- [ ] 오래된 이벤트·순서 역전·동일 상태 변경 차단 구현
- [x] 이벤트 표준화 및 메시지 변환 구현
- [x] 인증 실패·잘못된 payload·처리 실패 오류 응답 정의
- [x] 수신 API를 Swagger에서 제외해 인증정보·운영 입력값 노출 방지
### Phase 3. 네이버웍스 클라이언트
- [x] 액세스 토큰 발급·캐시·만료 갱신 구현
- [x] Bot 메시지 발송 함수 구현
- [x] API rate limit·일시 오류 기본 재시도 처리
- [ ] 4xx·5xx별 재시도 정책과 circuit breaker 구현
- [ ] 테스트용 발송 기능 구현
- [x] 비밀값이 로그에 노출되지 않도록 구현
### Phase 4. 이벤트별 알림
- [x] 신규 피드백 메시지 템플릿 구현
- [x] 상태 변경 메시지 템플릿 구현
- [x] 피드백 상태 변경 저장 경로에서 실제 변경 시 상태 이벤트 발생 구현
- [x] 관리자 공개 댓글 메시지 템플릿 구현
- [x] 담당자·프로젝트 관리자·피드백 작성자 라우팅 구현
- [x] 이벤트별 중복 수신자 제거 및 계정 매핑 실패 격리 처리 구현
- [x] 비밀글·내부 메모 공개 범위 처리
- [x] 상세 페이지 링크 생성
### Phase 5. 발송 이력과 장애 대응
- [x] 알림 발송 로그 모델 추가
- [x] 성공·실패·재시도 상태 저장
- [x] 중복 발송 방지용 idempotency key 저장
- [x] 네이버웍스 장애 시 원본 이벤트 유실 방지
- [ ] 발송량 제한·폭주 제어·kill switch 구현
- [x] 내부 메모리·Bot 자기 이벤트의 외부 알림 차단
- [ ] 관리자 화면 또는 운영 로그에서 실패 건 확인 가능하게 구성
### Phase 6. 검증 및 배포
- [ ] 단위 테스트: 서명 검증·이벤트 변환·템플릿·라우팅
- [ ] 통합 테스트: Webhook 수신부터 네이버웍스 client mock 발송까지
- [ ] 스테이징 실제 Bot 방으로 신규 피드백 테스트
- [ ] 상태 변경 중복 발송 테스트
- [ ] 공개 댓글과 내부 메모의 수신 범위 테스트
- [ ] 네이버웍스 인증 실패·timeout·재시도 테스트
- [ ] 위조 서명·오래된 timestamp·중복·순서 역전 이벤트 테스트
- [ ] 허용되지 않은 프로젝트·수신자·비밀글·내부 메모 차단 테스트
- [ ] 폭주·circuit breaker·kill switch·재처리 테스트
- [x] Gitea Actions의 Variables/Secrets를 스테이징 API 컨테이너까지 전달하도록 배포 설정 연결
- [ ] 스테이징 환경변수와 HTTPS 외부 Webhook URL 확인
- [ ] 운영 전 비밀값 회전 및 테스트 로그 정리
### 6.1 로컬 적용 및 검증 결과 (2026-08-26)
- [x] `notification_deliveries` 마이그레이션 로컬 적용 확인
- [x] `GET http://127.0.0.1:4000/api/health` 응답 `200`, database `up` 확인
- [x] `POST http://127.0.0.1:4000/api/integrations/abc/webhooks` 응답 `202`, 로컬 발송 비활성 응답 확인
- [x] API·웹 타입체크 및 린트 통과
- [x] 기존 Webhook listener 단위 테스트 22건 통과
- [x] 완료·진행하지 않음을 포함한 상태 변경 이벤트 중복 발송 방지 로직 보완 및 API 정적 검사 통과
- [ ] 네이버웍스 실제 Bot 메시지 발송 확인 — 로컬 자격증명 미설정
- [ ] ABC에서 외부 Webhook을 실제로 보내는 end-to-end 확인 — ABC 관리자 설정 필요
## 8. 완료 기준
- [ ] 허용된 ABC Webhook만 인증 후 처리된다.
- [ ] 신규 피드백 등록 시 지정된 네이버웍스 수신자에게 한 번만 알림이 도착한다.
- [ ] 피드백 상태가 실제로 변경될 때 이전 상태와 현재 상태가 포함된 알림이 도착한다.
- [ ] 관리자 공개 댓글 등록 시 정책에 맞는 수신자에게 알림이 도착한다.
- [ ] 내부 메모가 작성자에게 노출되지 않는다.
- [ ] 네이버웍스 장애가 발생해도 Webhook 요청과 발송 실패 이력이 유실되지 않는다.
- [x] 토큰·시크릿·개인키가 소스, API 응답, 로그에 노출되지 않는다.
- [ ] 새로운 이벤트를 추가할 때 수신 라우터의 핵심 흐름을 변경하지 않고 이벤트 매퍼·라우터·템플릿만 추가할 수 있다.
## 9. 사용자가 별도로 해야 하는 작업
1. 네이버웍스 Bot과 테스트용 방을 만들고 Bot을 방에 초대한다.
2. 네이버웍스 개발자 콘솔에서 Bot 메시지 발송 권한과 인증정보를 발급한다.
3. 로컬 `.env`에 네이버웍스 인증정보를 직접 입력한다. 값은 저장소·README·채팅에 올리지 않는다.
4. 로컬 검증 시 다음 플래그를 켠 뒤 API를 재시작한다.
ABC_WEBHOOK_ENABLED=true
ABC_WEBHOOK_TOKEN=<ABC에서 설정한 수신 토큰>
NAVER_WORKS_ENABLED=true
NAVER_WORKS_BOT_ID=<Bot ID>
NAVER_WORKS_DEFAULT_ROOM_ID=<테스트 방 ID>
HMAC 서명을 사용할 경우 `ABC_WEBHOOK_TOKEN` 대신 `ABC_WEBHOOK_SIGNING_SECRET`을 설정한다.
5. ABC 관리자 화면에서 Webhook URL을 `https://<외부주소>/api/integrations/abc/webhooks`로 등록하고, 신규 피드백·상태 변경·관리자 공개 댓글 이벤트를 선택한다.
6. 신규 피드백 등록, 피드백 상태 변경, 관리자 공개 댓글 등록을 각각 1회씩 실행해 네이버웍스 수신 여부와 `notification_deliveries` 기록을 확인한다.
7. 내부 메모, 비밀글, 중복 Webhook, 잘못된 토큰 요청이 알림으로 전송되지 않는지 확인한다.
## 10. 우선 결정할 입력값
구현 시작 전에 다음 네 가지만 먼저 확정한다.
1. 네이버웍스 수신 방식: 특정 방 1개인지, 사용자별 Bot 메시지인지
2. 신규 피드백·상태 변경·댓글별 수신 대상
3. ABC Webhook의 실제 payload와 인증 방식
4. 스테이징에서 사용할 외부 Webhook URL과 네이버웍스 테스트 방