# notification
**Repository Path**: ksdhy/notification
## Basic Information
- **Project Name**: notification
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-08-26
- **Last Updated**: 2026-08-26
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 接单通知服务(Notification Service)
其他业务服务通过 HTTP 调用本服务发送通知。第一版支持**邮件(通用 SMTP)**,
按「通道(channel)」抽象设计,新增通道(SMS / Webhook / 企业微信 / 钉钉 / Push …)成本极低。
- 技术栈:Node.js + TypeScript + NestJS 11
- 邮件:nodemailer 通用 SMTP(QQ / 163 / Gmail / 企业邮箱等)
- 进程托管:pm2(本机)
- 设计要点:HTTP 触发 → `NotificationService` 按 `channel` 路由 → 对应 `Provider` 发送
## 目录结构
```
src/
├── main.ts # 启动:helmet / cors / swagger / 监听
├── app.module.ts # 根模块 + 全局 pipe/filter/interceptor
├── config/ # 配置:.env 加载 + Joi 启动校验
├── common/ # 横切:异常过滤器 / 日志 / 重试 / 工具
├── health/ # GET /health
└── notifications/
├── notifications.controller.ts # POST /notifications/send
├── notifications.service.ts # channel → provider 路由(核心)
├── dto/ # 请求体 DTO
└── providers/
├── notification-provider.interface.ts # 通道抽象接口(核心)
└── email/ # 邮件通道实现
```
## 安装
```bash
npm install
cp .env.example .env # 然后编辑 .env 填配置
```
## 配置(.env)
| 变量 | 说明 |
|---|---|
| `PORT` | HTTP 端口,默认 3000 |
| `MAIL_TRANSPORT` | `smtp`(真实发送)或 `ethereal`(测试模式,无需真实邮箱) |
| `SMTP_HOST/PORT/SECURE/USER/PASS/FROM` | SMTP 配置,仅 `smtp` 模式必填 |
| `SMTP_VERIFY_CONNECT_ON_BOOT` | 启动时校验 SMTP 连通性,默认 false |
> **⚠️ 授权码坑**:QQ / 163 / Gmail 的 `SMTP_PASS` 不是邮箱登录密码,而是邮箱后台开启 SMTP 后生成的**授权码 / 客户端专用密码**。
> - QQ:设置 → 账户 → 开启 IMAP/SMTP 服务 → 生成授权码
> - 163:设置 → POP3/SMTP/IMAP → 开启 → 设置客户端授权密码
> - Gmail:开启两步验证后生成「应用专用密码」
## 本地开发
```bash
npm run start:dev # 热重载,监听 :3000
```
默认 `.env` 为 `ethereal` 测试模式:发邮件不真实投递,响应里返回 `previewUrl`,浏览器打开即可看到邮件内容。
切换为真实发送:把 `MAIL_TRANSPORT` 改为 `smtp` 并填好 `SMTP_*`。
## pm2 托管
```bash
npm run build
pm2 start ecosystem.config.cjs
pm2 logs notification-service
pm2 restart notification-service # 改完代码重新 build 后重启
pm2 save
```
## API
### 健康检查
```bash
curl -s http://localhost:3000/health
# { "success": true, "data": { "status": "ok", "timestamp": "..." } }
```
### 发送通知
```bash
curl -s -X POST http://localhost:3000/notifications/send \
-H "Content-Type: application/json" \
-d '{
"channel": "email",
"to": "user@example.com",
"subject": "新订单通知 #1024",
"html": "您有一笔新订单"
}'
```
成功响应:
```json
{
"success": true,
"data": {
"channel": "email",
"success": true,
"messageId": "...",
"previewUrl": "https://ethereal.email/message/...",
"sentAt": "2026-08-03T..."
}
}
```
失败响应(统一格式,带 traceId):
```json
{
"success": false,
"error": { "code": "UNSUPPORTED_CHANNEL", "message": "...", "details": { "supported": ["email"] }, "traceId": "..." },
"timestamp": "...",
"path": "/notifications/send"
}
```
常用错误码:`UNSUPPORTED_CHANNEL`(400)/ `SEND_FAILED`(502)/ 校验失败(400)。
Swagger 契约文档:启动后访问 `http://localhost:3000/docs`。
## 新增通道(以 SMS 为例)
核心 `controller/service/DTO/接口` 一行不改,只需:
1. 新建 `src/notifications/providers/sms/sms.provider.ts`:
```ts
import { Injectable, Logger } from '@nestjs/common';
import { INotificationProvider, SendRequest, SendResult } from '../notification-provider.interface';
@Injectable()
export class SmsProvider implements INotificationProvider {
private readonly logger = new Logger(SmsProvider.name);
readonly channel = 'sms' as const;
async send(req: SendRequest): Promise {
this.logger.log(`SMS -> ${req.to}: ${req.text ?? req.subject}`);
return { channel: this.channel, success: true, messageId: `sms-${Date.now()}`, sentAt: new Date().toISOString() };
}
}
```
2. 新建 `src/notifications/providers/sms/sms.module.ts`:
```ts
import { Module } from '@nestjs/common';
import { SmsProvider } from './sms.provider';
@Module({ providers: [SmsProvider], exports: [SmsProvider] })
export class SmsModule {}
```
3. 在 `notifications.module.ts` 注册(两处):
```ts
imports: [EmailModule, SmsModule],
// ...
useFactory: (email: EmailProvider, sms: SmsProvider) => [email, sms],
inject: [EmailProvider, SmsProvider],
```
重启后即可 `curl ... -d '{"channel":"sms","to":"13800000000","text":"验证码 1234"}'`。
## 鉴权(本期未启用)
本机自用、不暴露公网,因此未做鉴权。如需开启,新增一个 `AuthGuard implements CanActivate`,
在 `app.module.ts` 加一行 `{ provide: APP_GUARD, useClass: AuthGuard }` 即可,**不改任何业务代码**。
## 可靠性
- 同步发送 + 3 次指数退避重试(处理 SMTP 瞬时失败)。
- 结构化日志:每次发送记录通道 / 收件人(脱敏) / 结果 / 耗时。
- 未来扩展点:发送动作收敛在各 `provider.send()` 内,`NotificationService` 只做路由,
后续若需异步可靠投递,把 `provider.send(...)` 包成 BullMQ 任务只需改 service 一处。