# 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 一处。