开发指南
开发环境搭建
系统要求
- 操作系统: macOS / Windows / Linux
- Node.js: >= 18.0.0
- Java: >= 17.0.0(后端服务)
- 包管理器: npm >= 9.0.0 或 pnpm >= 8.0.0
- Git: >= 2.30.0
- MySQL: >= 8.0
- Redis: >= 6.0
推荐工具
- IDE: VSCode / WebStorm / IntelliJ IDEA
- 浏览器: Chrome / Edge / Safari(最新版)
- 数据库工具: DBeaver / Navicat
- API 调试: Postman / Apifox
项目架构
技术栈
| 层级 | 技术 |
|---|---|
| 前端框架 | Vue 3 + TypeScript |
| 状态管理 | Pinia |
| 路由 | Vue Router |
| UI 组件 | Ant Design Vue |
| 构建工具 | Vite |
| 后端框架 | Spring Boot / Spring Cloud |
| 消息队列 | RabbitMQ / Kafka |
| 缓存 | Redis |
| 数据库 | MySQL / PostgreSQL |
| 对象存储 | MinIO / 阿里云 OSS |
目录结构
pushreach/
├── apps/ # 应用层
│ ├── web/ # Web 管理后台
│ ├── mobile/ # 移动端应用
│ └── desktop/ # 桌面端应用
├── packages/ # 共享包
│ ├── sdk/ # PushReach SDK
│ ├── ui/ # UI 组件库
│ ├── shared/ # 共享工具
│ └── types/ # 类型定义
├── server/ # 服务端
│ ├── gateway/ # API 网关
│ ├── message/ # 消息服务
│ ├── channel/ # 渠道适配器
│ ├── template/ # 模板服务
│ ├── router/ # 路由引擎
│ ├── orchestration/ # 编排引擎
│ ├── analytics/ # 数据分析
│ └── tenant/ # 租户服务
├── docs/ # 文档
└── scripts/ # 脚本工具开发规范
代码规范
- 使用 ESLint + Prettier 进行代码格式化
- 遵循 Vue 3 组合式 API 风格
- TypeScript 严格模式启用
- 组件命名使用 PascalCase
- 函数命名使用 camelCase
Git 规范
类型(scope): 简短描述
详细描述(可选)
Footer(可选)类型说明:
feat: 新功能fix: 修复docs: 文档style: 格式refactor: 重构perf: 性能优化test: 测试chore: 构建/工具
示例:
feat(channel): 添加飞书渠道适配器
- 支持飞书应用消息发送
- 支持飞书群消息发送
- 支持飞书机器人消息发送
Closes #123分支管理
main: 主分支,稳定版本develop: 开发分支feature/*: 功能分支hotfix/*: 紧急修复release/*: 发布分支
渠道适配器开发
适配器接口
typescript
interface ChannelAdapter {
name: string
type: ChannelType
send(message: ChannelMessage): Promise<SendResult>
batchSend(messages: ChannelMessage[]): Promise<BatchSendResult>
checkHealth(): Promise<HealthStatus>
getQuota(): Promise<QuotaInfo>
}实现自定义适配器
typescript
import { ChannelAdapter, ChannelMessage, SendResult } from '@pushreach/sdk'
export class CustomChannelAdapter implements ChannelAdapter {
name = 'custom-channel'
type = 'custom' as ChannelType
async send(message: ChannelMessage): Promise<SendResult> {
const response = await fetch('https://api.custom-channel.com/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.config.apiKey}`
},
body: JSON.stringify({
to: message.receivers,
content: message.content,
template_id: message.templateId
})
})
const result = await response.json()
return {
success: result.code === 0,
messageId: result.data.message_id,
channelMessageId: result.data.request_id
}
}
async batchSend(messages: ChannelMessage[]): Promise<BatchSendResult> {
const results = await Promise.allSettled(
messages.map(msg => this.send(msg))
)
return {
total: messages.length,
success: results.filter(r => r.status === 'fulfilled').length,
failed: results.filter(r => r.status === 'rejected').length,
results
}
}
async checkHealth(): Promise<HealthStatus> {
try {
const response = await fetch('https://api.custom-channel.com/health')
return { healthy: response.ok, latency: 0 }
} catch {
return { healthy: false, latency: -1 }
}
}
async getQuota(): Promise<QuotaInfo> {
return {
used: 0,
total: 10000,
remaining: 10000,
resetAt: new Date()
}
}
}注册适配器
typescript
import { PushReachClient } from '@pushreach/sdk'
import { CustomChannelAdapter } from './custom-adapter'
const client = new PushReachClient({
apiKey: 'your_api_key',
apiSecret: 'your_api_secret'
})
client.registerAdapter(new CustomChannelAdapter({
apiKey: 'your_channel_api_key'
}))路由引擎开发
路由策略接口
typescript
interface RoutingStrategy {
name: string
selectChannel(
context: RoutingContext,
channels: ChannelInfo[]
): Promise<ChannelInfo>
}实现自定义路由策略
typescript
export class CostFirstStrategy implements RoutingStrategy {
name = 'cost_first'
async selectChannel(
context: RoutingContext,
channels: ChannelInfo[]
): Promise<ChannelInfo> {
const availableChannels = channels.filter(
ch => ch.healthy && ch.quotaRemaining > 0
)
return availableChannels.sort(
(a, b) => a.costPerMessage - b.costPerMessage
)[0]
}
}模板引擎开发
模板渲染
typescript
import { TemplateEngine } from '@pushreach/sdk'
const engine = new TemplateEngine()
const result = engine.render('欢迎 {{username}},您的验证码是 {{code}}', {
username: '张三',
code: '123456'
})
console.log(result)
// 输出: 欢迎 张三,您的验证码是 123456条件渲染
typescript
const template = `
{{#if vip}}
尊敬的 VIP 会员 {{username}},您有专属优惠!
{{else}}
亲爱的 {{username}},升级 VIP 享更多权益!
{{/if}}
`
const result = engine.render(template, {
username: '张三',
vip: true
})测试
单元测试
bash
# 运行所有测试
npm run test
# 运行指定模块测试
npm run test -- packages/sdk
# 覆盖率报告
npm run test:coverage集成测试
bash
# 运行渠道适配器集成测试
npm run test:integration -- --channel=sms
npm run test:integration -- --channel=email
npm run test:integration -- --channel=wechatE2E 测试
bash
# 运行 E2E 测试
npm run test:e2e
# headed 模式
npm run test:e2e -- --headed性能优化
消息发送优化
- 批量合并: 多条消息合并发送,减少 API 调用次数
- 连接池: HTTP 连接复用,减少连接建立开销
- 异步发送: 消息异步处理,不阻塞主线程
- 限流保护: 令牌桶算法,防止渠道过载
数据库优化
- 索引优化: 消息表按时间分区,查询效率提升
- 读写分离: 查询走从库,写入走主库
- 缓存策略: 热点数据 Redis 缓存,减少数据库压力
- 分库分表: 大数据量水平拆分
消息队列优化
- 消息分片: 按租户/渠道分片,提高并发处理能力
- 消费组: 多消费者并行消费,提升吞吐量
- 死信队列: 处理失败消息,避免阻塞正常消费
- 延迟队列: 支持定时发送与延迟重试
部署
Docker 部署
bash
# 构建镜像
docker build -t pushreach:latest .
# 运行容器
docker run -d -p 8080:8080 pushreach:latestDocker Compose 部署
bash
# 启动所有服务
docker-compose up -d
# 查看服务状态
docker-compose psKubernetes 部署
bash
# 应用配置
kubectl apply -f k8s/
# 查看状态
kubectl get pods -n pushreach常见问题
Q: 渠道发送超时如何处理?
A: PushReach 内置超时重试机制,可在渠道配置中设置超时时间和重试策略。
Q: 如何保证消息不丢失?
A: 消息持久化存储 + 消息队列确认机制 + 失败重试策略,三重保障消息不丢失。
Q: 如何实现多租户数据隔离?
A: 通过租户 ID 字段隔离 + 行级安全策略(RLS),确保租户间数据完全隔离。
Q: 如何监控渠道健康状态?
A: PushReach 内置渠道健康检测,定时探测渠道可用性,异常时自动告警并切换备用渠道。