@k-msg/webhook 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,418 @@
1
+ # @k-msg/webhook-system
2
+
3
+ 실시간 메시지 이벤트 알림을 위한 엔터프라이즈급 Webhook 시스템입니다.
4
+
5
+ ## ✨ 주요 기능
6
+
7
+ - 🚀 **비동기 이벤트 디스패칭**: 고성능 병렬 웹훅 전송
8
+ - 🔄 **스마트 재시도**: 지수 백오프와 지터를 사용한 재시도 로직
9
+ - 🔒 **보안**: HMAC 서명 및 타임스탬프 검증
10
+ - 📊 **모니터링**: 전송 통계 및 실패 추적
11
+ - 🎯 **필터링**: 이벤트 타입 및 메타데이터 기반 필터링
12
+ - 📦 **배치 처리**: 대량 이벤트 효율적 처리
13
+
14
+ ## 📦 설치
15
+
16
+ ```bash
17
+ npm install @k-msg/webhook-system
18
+ # 또는
19
+ bun add @k-msg/webhook-system
20
+ ```
21
+
22
+ ## 🚀 빠른 시작
23
+
24
+ ### 1. 기본 설정
25
+
26
+ ```typescript
27
+ import {
28
+ WebhookService,
29
+ WebhookRegistry,
30
+ WebhookDispatcher,
31
+ SecurityManager,
32
+ RetryManager,
33
+ WebhookEventType
34
+ } from '@k-msg/webhook-system';
35
+
36
+ // 웹훅 시스템 초기화
37
+ const registry = new WebhookRegistry();
38
+ const securityManager = new SecurityManager();
39
+ const retryManager = new RetryManager();
40
+ const dispatcher = new WebhookDispatcher(registry, securityManager, retryManager);
41
+
42
+ const webhookService = new WebhookService({
43
+ maxRetries: 3,
44
+ retryDelayMs: 1000,
45
+ timeoutMs: 30000,
46
+ enableSecurity: true,
47
+ secretKey: 'your-webhook-secret',
48
+ enabledEvents: [
49
+ WebhookEventType.MESSAGE_SENT,
50
+ WebhookEventType.MESSAGE_DELIVERED,
51
+ WebhookEventType.TEMPLATE_APPROVED
52
+ ],
53
+ batchSize: 10,
54
+ batchTimeoutMs: 5000
55
+ });
56
+ ```
57
+
58
+ ### 2. 웹훅 엔드포인트 등록
59
+
60
+ ```typescript
61
+ const endpoint = {
62
+ id: 'endpoint-1',
63
+ url: 'https://your-app.com/webhooks',
64
+ name: 'My App Webhook',
65
+ description: 'Receives message events',
66
+ active: true,
67
+ events: [
68
+ WebhookEventType.MESSAGE_SENT,
69
+ WebhookEventType.MESSAGE_DELIVERED,
70
+ WebhookEventType.MESSAGE_FAILED
71
+ ],
72
+ secret: 'your-endpoint-secret',
73
+ retryConfig: {
74
+ maxRetries: 5,
75
+ retryDelayMs: 2000,
76
+ backoffMultiplier: 2
77
+ },
78
+ filters: {
79
+ providerId: ['iwinv', 'aligo'],
80
+ channelId: ['channel-1']
81
+ },
82
+ createdAt: new Date(),
83
+ updatedAt: new Date(),
84
+ status: 'active' as const
85
+ };
86
+
87
+ await webhookService.registerEndpoint(endpoint);
88
+ ```
89
+
90
+ ### 3. 이벤트 발송
91
+
92
+ ```typescript
93
+ // 단일 이벤트 발송
94
+ const event = {
95
+ id: 'evt_123',
96
+ type: WebhookEventType.MESSAGE_SENT,
97
+ timestamp: new Date(),
98
+ data: {
99
+ messageId: 'msg_456',
100
+ templateId: 'tmpl_789',
101
+ phoneNumber: '01012345678',
102
+ status: 'sent'
103
+ },
104
+ metadata: {
105
+ providerId: 'iwinv',
106
+ channelId: 'channel-1',
107
+ templateId: 'tmpl_789',
108
+ messageId: 'msg_456',
109
+ correlationId: 'req_abc'
110
+ },
111
+ version: '1.0'
112
+ };
113
+
114
+ await webhookService.dispatchEvent(event);
115
+
116
+ // 배치 이벤트 발송
117
+ const events = [event1, event2, event3];
118
+ await webhookService.dispatchEvents(events);
119
+ ```
120
+
121
+ ## 📋 이벤트 타입
122
+
123
+ 웹훅 시스템은 다음과 같은 이벤트 타입을 지원합니다:
124
+
125
+ ### 메시지 이벤트
126
+
127
+ - `message.sent` - 메시지 발송 완료
128
+ - `message.delivered` - 메시지 전달 완료
129
+ - `message.failed` - 메시지 발송 실패
130
+ - `message.clicked` - 메시지 클릭
131
+ - `message.read` - 메시지 읽음
132
+
133
+ ### 템플릿 이벤트
134
+
135
+ - `template.created` - 템플릿 생성
136
+ - `template.approved` - 템플릿 승인
137
+ - `template.rejected` - 템플릿 거부
138
+ - `template.updated` - 템플릿 수정
139
+ - `template.deleted` - 템플릿 삭제
140
+
141
+ ### 채널 이벤트
142
+
143
+ - `channel.created` - 채널 생성
144
+ - `channel.verified` - 채널 인증
145
+ - `sender_number.added` - 발신번호 추가
146
+ - `sender_number.verified` - 발신번호 인증
147
+
148
+ ### 시스템 이벤트
149
+
150
+ - `system.quota_warning` - 할당량 경고
151
+ - `system.quota_exceeded` - 할당량 초과
152
+ - `system.provider_error` - 프로바이더 오류
153
+ - `system.maintenance` - 시스템 점검
154
+
155
+ ### 분석 이벤트
156
+
157
+ - `analytics.anomaly_detected` - 이상 징후 감지
158
+ - `analytics.threshold_exceeded` - 임계값 초과
159
+
160
+ ## 🔒 보안
161
+
162
+ ### HMAC 서명 검증
163
+
164
+ 웹훅 요청은 HMAC-SHA256으로 서명됩니다:
165
+
166
+ ```typescript
167
+ // 서명 생성 (자동)
168
+ const securityManager = new SecurityManager({
169
+ algorithm: 'sha256',
170
+ header: 'X-Webhook-Signature',
171
+ prefix: 'sha256='
172
+ });
173
+
174
+ // 수신측에서 서명 검증
175
+ const payload = req.body;
176
+ const signature = req.headers['X-Webhook-Signature'];
177
+ const secret = process.env.WEBHOOK_SECRET;
178
+
179
+ const isValid = securityManager.verifySignature(payload, signature, secret);
180
+ if (!isValid) {
181
+ return res.status(401).json({ error: 'Invalid signature' });
182
+ }
183
+ ```
184
+
185
+ ### 타임스탬프 검증
186
+
187
+ 재생 공격을 방지하기 위한 타임스탬프 검증:
188
+
189
+ ```typescript
190
+ const timestamp = req.headers['X-Webhook-Timestamp'];
191
+ const isValidTime = securityManager.verifyTimestamp(timestamp, 300); // 5분 허용
192
+
193
+ if (!isValidTime) {
194
+ return res.status(401).json({ error: 'Request too old' });
195
+ }
196
+ ```
197
+
198
+ ## 🔄 재시도 정책
199
+
200
+ ### 설정
201
+
202
+ ```typescript
203
+ const retryManager = new RetryManager({
204
+ maxRetries: 3,
205
+ baseDelayMs: 1000,
206
+ maxDelayMs: 300000, // 5분
207
+ backoffMultiplier: 2,
208
+ jitter: true
209
+ });
210
+ ```
211
+
212
+ ### 재시도 조건
213
+
214
+ - **네트워크 오류**: 연결 실패, 타임아웃 등
215
+ - **5xx 서버 오류**: 일시적 서버 문제
216
+ - **429 Too Many Requests**: 요청 제한
217
+ - **408 Request Timeout**: 요청 타임아웃
218
+
219
+ ### 재시도하지 않는 조건
220
+
221
+ - **4xx 클라이언트 오류** (429, 408 제외)
222
+ - **최대 재시도 횟수 초과**
223
+ - **성공적 응답** (2xx, 3xx)
224
+
225
+ ## 📊 모니터링 및 통계
226
+
227
+ ### 웹훅 통계 조회
228
+
229
+ ```typescript
230
+ // 전체 통계
231
+ const stats = await webhookService.getStats();
232
+ console.log(stats);
233
+ // {
234
+ // totalEndpoints: 5,
235
+ // activeEndpoints: 4,
236
+ // totalDeliveries: 1250,
237
+ // successfulDeliveries: 1180,
238
+ // failedDeliveries: 70,
239
+ // averageLatency: 245,
240
+ // successRate: 94.4
241
+ // }
242
+
243
+ // 특정 엔드포인트 통계
244
+ const endpointStats = await webhookService.getEndpointStats('endpoint-1', {
245
+ start: new Date('2024-01-01'),
246
+ end: new Date('2024-01-31')
247
+ });
248
+ ```
249
+
250
+ ### 실패한 전송 조회
251
+
252
+ ```typescript
253
+ // 실패한 전송 내역
254
+ const failedDeliveries = await webhookService.getFailedDeliveries('endpoint-1');
255
+
256
+ failedDeliveries.forEach(delivery => {
257
+ console.log(`Delivery ${delivery.id} failed:`, delivery.attempts[0].error);
258
+ });
259
+ ```
260
+
261
+ ## 🎯 고급 기능
262
+
263
+ ### 이벤트 필터링
264
+
265
+ 엔드포인트별로 세밀한 이벤트 필터링 가능:
266
+
267
+ ```typescript
268
+ const endpoint = {
269
+ id: 'filtered-endpoint',
270
+ url: 'https://app.com/webhooks',
271
+ events: [WebhookEventType.MESSAGE_SENT],
272
+ filters: {
273
+ providerId: ['iwinv'], // IWINV 프로바이더만
274
+ channelId: ['channel-marketing'], // 마케팅 채널만
275
+ templateId: ['welcome-template'] // 환영 템플릿만
276
+ },
277
+ // ... 기타 설정
278
+ };
279
+ ```
280
+
281
+ ### 배치 처리
282
+
283
+ 대량 이벤트를 효율적으로 처리:
284
+
285
+ ```typescript
286
+ const webhookService = new WebhookService({
287
+ batchSize: 50,
288
+ batchTimeoutMs: 10000, // 10초마다 또는 50개씩 배치 처리
289
+ // ... 기타 설정
290
+ });
291
+
292
+ // 배치가 자동으로 처리됨
293
+ await webhookService.dispatchEvent(event1);
294
+ await webhookService.dispatchEvent(event2);
295
+ // ... 더 많은 이벤트
296
+ ```
297
+
298
+ ### 엔드포인트 테스트
299
+
300
+ 웹훅 엔드포인트의 연결성 테스트:
301
+
302
+ ```typescript
303
+ const testResult = await webhookService.testEndpoint('endpoint-1');
304
+
305
+ if (testResult.success) {
306
+ console.log(`✅ Endpoint is healthy (${testResult.responseTime}ms)`);
307
+ } else {
308
+ console.log(`❌ Endpoint failed: ${testResult.error}`);
309
+ }
310
+ ```
311
+
312
+ ## 🛠️ Express/Hono와 통합
313
+
314
+ ### Express 미들웨어
315
+
316
+ ```typescript
317
+ import express from 'express';
318
+
319
+ const app = express();
320
+
321
+ // 웹훅 검증 미들웨어
322
+ const verifyWebhook = (req, res, next) => {
323
+ const signature = req.headers['x-webhook-signature'];
324
+ const payload = JSON.stringify(req.body);
325
+
326
+ if (!securityManager.verifySignature(payload, signature, process.env.WEBHOOK_SECRET)) {
327
+ return res.status(401).json({ error: 'Invalid signature' });
328
+ }
329
+
330
+ next();
331
+ };
332
+
333
+ app.post('/webhooks', verifyWebhook, (req, res) => {
334
+ const event = req.body;
335
+
336
+ console.log(`Received ${event.type} event:`, event.data);
337
+
338
+ // TODO: 이벤트 처리 로직
339
+
340
+ res.json({ success: true });
341
+ });
342
+ ```
343
+
344
+ ### Hono 통합
345
+
346
+ ```typescript
347
+ import { Hono } from 'hono';
348
+
349
+ const app = new Hono();
350
+
351
+ app.post('/webhooks', async (c) => {
352
+ const signature = c.req.header('X-Webhook-Signature');
353
+ const payload = await c.req.text();
354
+
355
+ if (!securityManager.verifySignature(payload, signature, process.env.WEBHOOK_SECRET)) {
356
+ return c.json({ error: 'Invalid signature' }, 401);
357
+ }
358
+
359
+ const event = JSON.parse(payload);
360
+
361
+ // TODO: 이벤트 처리
362
+ console.log(`Processing ${event.type}:`, event.data);
363
+
364
+ return c.json({ success: true });
365
+ });
366
+ ```
367
+
368
+ ## 🔧 설정 옵션
369
+
370
+ ### WebhookConfig
371
+
372
+ ```typescript
373
+ interface WebhookConfig {
374
+ maxRetries: number; // 최대 재시도 횟수 (기본: 3)
375
+ retryDelayMs: number; // 재시도 기본 지연시간 (기본: 1000ms)
376
+ timeoutMs: number; // 요청 타임아웃 (기본: 30000ms)
377
+ enableSecurity: boolean; // 보안 기능 활성화 (기본: true)
378
+ secretKey?: string; // 기본 시크릿 키
379
+ enabledEvents: WebhookEventType[]; // 활성화할 이벤트 타입들
380
+ batchSize: number; // 배치 크기 (기본: 10)
381
+ batchTimeoutMs: number; // 배치 타임아웃 (기본: 5000ms)
382
+ }
383
+ ```
384
+
385
+ ### RetryConfig
386
+
387
+ ```typescript
388
+ interface RetryConfig {
389
+ maxRetries: number; // 최대 재시도 횟수
390
+ baseDelayMs: number; // 기본 지연시간
391
+ maxDelayMs: number; // 최대 지연시간
392
+ backoffMultiplier: number; // 백오프 배수
393
+ jitter: boolean; // 지터 활성화 (랜덤성 추가)
394
+ }
395
+ ```
396
+
397
+ ## 📝 예제
398
+
399
+ 전체 예제는 [examples](./examples/) 디렉토리를 참조하세요:
400
+
401
+ - [기본 사용법](./examples/basic-usage.ts)
402
+ - [Express 통합](./examples/express-integration.ts)
403
+ - [대량 처리](./examples/batch-processing.ts)
404
+ - [고급 필터링](./examples/advanced-filtering.ts)
405
+
406
+ ## 🤝 기여하기
407
+
408
+ 기여를 환영합니다! [CONTRIBUTING.md](../../CONTRIBUTING.md)를 참조하세요.
409
+
410
+ ## 📄 라이선스
411
+
412
+ MIT License - [LICENSE](../../LICENSE) 파일을 참조하세요.
413
+
414
+ ---
415
+
416
+ **K-Message** - 한국형 멀티채널 메시징 플랫폼
417
+
418
+ 🌟 [GitHub](https://github.com/imjlk/k-message) | 📖 [Documentation](https://k-message.dev) | 💬 [Discord](https://discord.gg/k-message)