Skip to content

开发指南

开发环境搭建

系统要求

  • 操作系统: 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=wechat

E2E 测试

bash
# 运行 E2E 测试
npm run test:e2e

# headed 模式
npm run test:e2e -- --headed

性能优化

消息发送优化

  1. 批量合并: 多条消息合并发送,减少 API 调用次数
  2. 连接池: HTTP 连接复用,减少连接建立开销
  3. 异步发送: 消息异步处理,不阻塞主线程
  4. 限流保护: 令牌桶算法,防止渠道过载

数据库优化

  1. 索引优化: 消息表按时间分区,查询效率提升
  2. 读写分离: 查询走从库,写入走主库
  3. 缓存策略: 热点数据 Redis 缓存,减少数据库压力
  4. 分库分表: 大数据量水平拆分

消息队列优化

  1. 消息分片: 按租户/渠道分片,提高并发处理能力
  2. 消费组: 多消费者并行消费,提升吞吐量
  3. 死信队列: 处理失败消息,避免阻塞正常消费
  4. 延迟队列: 支持定时发送与延迟重试

部署

Docker 部署

bash
# 构建镜像
docker build -t pushreach:latest .

# 运行容器
docker run -d -p 8080:8080 pushreach:latest

Docker Compose 部署

bash
# 启动所有服务
docker-compose up -d

# 查看服务状态
docker-compose ps

Kubernetes 部署

bash
# 应用配置
kubectl apply -f k8s/

# 查看状态
kubectl get pods -n pushreach

常见问题

Q: 渠道发送超时如何处理?

A: PushReach 内置超时重试机制,可在渠道配置中设置超时时间和重试策略。

Q: 如何保证消息不丢失?

A: 消息持久化存储 + 消息队列确认机制 + 失败重试策略,三重保障消息不丢失。

Q: 如何实现多租户数据隔离?

A: 通过租户 ID 字段隔离 + 行级安全策略(RLS),确保租户间数据完全隔离。

Q: 如何监控渠道健康状态?

A: PushReach 内置渠道健康检测,定时探测渠道可用性,异常时自动告警并切换备用渠道。

相关资源