文档
开发指南功能特性活动通信系统

活动通信系统

活动通信系统

活动通信系统允许活动主办方向所有已注册的参与者主动发送邮件或短信通知。该系统具有发送次数限制和验证状态检查等安全特性。

功能概述

核心功能

  • 多渠道通信:支持邮件(EMAIL)和短信(SMS)两种发送方式
  • 批量发送:一次性向所有活动参与者发送消息
  • 发送限制:每个活动最多发送8次通信,防止垃圾信息
  • 验证检查:只发送给已验证邮箱或手机号的用户
  • 权限控制:只有活动主办方和管理员可以发送
  • 发送追踪:详细记录发送状态和统计信息

安全特性

  • 用户邮箱/手机号验证状态检查
  • 发送次数限制(每活动最多8次)
  • 权限验证(仅主办方和管理员)
  • 发送记录和审计日志

数据库设计

核心模型

EventCommunication(活动通信记录)

model EventCommunication {
  id              String              @id @default(cuid())
  eventId         String              // 活动ID
  sentBy          String              // 发送者ID
  type            CommunicationType   // 通信类型(EMAIL/SMS)
  subject         String              // 主题
  content         String              // 内容
  
  // 发送统计
  totalRecipients Int                 @default(0) // 总收件人数
  sentCount       Int                 @default(0) // 已发送数量
  deliveredCount  Int                 @default(0) // 投递成功数量
  failedCount     Int                 @default(0) // 失败数量
  
  // 发送状态
  status          CommunicationStatus @default(PENDING)
  scheduledAt     DateTime?           // 计划发送时间
  sentAt          DateTime?           // 实际发送时间
  
  createdAt       DateTime            @default(now())
  updatedAt       DateTime            @updatedAt
}

EventCommunicationRecord(具体发送记录)

model EventCommunicationRecord {
  id                  String               @id @default(cuid())
  communicationId     String               // 通信记录ID
  eventId             String               // 活动ID
  recipientId         String               // 收件人用户ID
  recipientEmail      String?              // 收件人邮箱
  recipientPhone      String?              // 收件人手机号
  
  // 发送状态
  status              CommunicationRecordStatus @default(PENDING)
  sentAt              DateTime?           // 发送时间
  deliveredAt         DateTime?           // 投递时间
  readAt              DateTime?           // 阅读时间
  errorMessage        String?             // 错误信息
  retryCount          Int                 @default(0) // 重试次数
}

发送限制管理

活动通信系统使用简洁的计数方式管理发送限制:

  • 限制机制:每个活动最多发送 8 次通信
  • 计数方式:直接统计 EventCommunication 表中该活动的记录数
  • 配置位置:在 event-communications.ts 中通过常量配置
const COMMUNICATION_LIMITS = {
  MAX_PER_EVENT: 8,
} as const;

API接口

1. 检查发送限制

GET /api/event-communications/:eventId/limit

响应示例:

{
  "data": {
    "canSend": true,
    "remainingCount": 6,
    "totalUsed": 2,
    "maxAllowed": 8
  }
}

2. 发送通信

POST /api/event-communications/:eventId/send
Content-Type: application/json

{
  "type": "EMAIL",
  "subject": "重要通知:活动时间变更",
  "content": "亲爱的参与者,由于天气原因,活动时间调整至...",
  "scheduledAt": null
}

响应示例:

{
  "data": {
    "id": "comm_123",
    "eventId": "event_456",
    "type": "EMAIL",
    "status": "SENDING",
    "totalRecipients": 25
  },
  "message": "通信发送已启动",
  "stats": {
    "totalRegistrations": 30,
    "validRecipients": 25,
    "unverifiedUsers": 5
  },
  "warning": "注意:有 5 个用户因为邮箱未验证而无法收到消息"
}

3. 获取通信历史

GET /api/event-communications/:eventId?page=1&limit=20

4. 重试失败发送

POST /api/event-communications/:eventId/:communicationId/retry

服务层实现

通信服务工厂

// src/lib/services/communication-service.ts
export class CommunicationServiceFactory {
  static getEmailService(): EmailService {
    if (process.env.NODE_ENV === 'development') {
      return new MockEmailService();
    }
    return new PlunkEmailService();
  }
  
  static getSMSService(): SMSService {
    if (process.env.NODE_ENV === 'development') {
      return new MockSMSService();
    }
    return new TencentSMSService();
  }
}

批量发送服务

export class BatchCommunicationService {
  async sendBatch(
    service: EmailService | SMSService,
    recipients: Recipient[],
    message: Message
  ): Promise<BatchSendResult> {
    // 批量发送逻辑
    // 支持重试机制和错误处理
  }
}

前端组件

主要组件结构

src/modules/dashboard/events/components/
├── EventCommunicationsPage.tsx      # 主页面组件
├── SendCommunicationForm.tsx        # 发送表单
├── CommunicationHistory.tsx         # 历史记录
└── CommunicationDetails.tsx         # 详情显示

使用示例

// 在活动管理页面中
<Link href={`/dashboard/events/${eventId}/communications`}>
  <Button variant="outline">
    <MessageSquare className="w-4 h-4" />
    通信
  </Button>
</Link>

验证机制详解

用户验证状态检查

系统会检查用户的邮箱和手机号验证状态:

// 邮件发送时检查 emailVerified 字段
const validEmailRecipients = registrations.filter(reg => 
  reg.user.email && reg.user.emailVerified === true
);

// 短信发送时检查 phoneNumberVerified 字段
const validSMSRecipients = registrations.filter(reg => 
  reg.user.phoneNumber && reg.user.phoneNumberVerified === true
);

未验证用户处理

  • 未验证用户会被自动跳过,不会收到消息
  • 系统会统计并显示未验证用户数量
  • 在确认发送时会显示警告信息

使用流程

1. 访问通信功能

  1. 进入活动管理页面
  2. 点击"通信"按钮进入通信管理页面

2. 发送新通信

  1. 选择通信类型(邮件或短信)
  2. 填写主题和内容
  3. 系统会显示已验证用户数量和发送限制信息
  4. 确认发送后开始批量处理

3. 查看历史记录

  1. 在"历史记录"标签页查看所有发送记录
  2. 可以查看详细的发送统计和状态
  3. 支持重试失败的发送

注意事项

发送限制

  • 每个活动最多发送8次通信
  • 通过直接统计 EventCommunication 表记录数量实现
  • 限制值通过代码常量配置,便于调整

验证要求

  • 只有已验证邮箱的用户才能收到邮件
  • 只有已验证手机号的用户才能收到短信
  • 未验证用户会被自动跳过

权限控制

  • 只有活动主办方可以发送通信
  • 活动管理员(具有编辑活动或管理报名权限)也可发送
  • 普通用户无法访问通信功能

开发环境

  • 开发环境使用Mock服务,不会真实发送
  • Mock服务会模拟发送过程和状态变化
  • 生产环境需要配置真实的邮件和短信服务商

环境配置

邮件服务(Plunk)

PLUNK_API_KEY=your_plunk_api_key

短信服务(腾讯云)

TENCENT_SMS_SECRET_ID=your_secret_id
TENCENT_SMS_SECRET_KEY=your_secret_key
TENCENT_SMS_REGION=ap-guangzhou
TENCENT_SMS_SDK_APP_ID=your_app_id
TENCENT_SMS_SIGN_NAME=your_sign_name
TENCENT_SMS_TEMPLATE_ID=your_template_id

⚠️ 腾讯云短信只在 ap-guangzhou 区域提供该接口,若配置为其他区域会出现 “The action not support this region” 报错。

扩展功能

未来可能的增强

  1. 模板系统:预设消息模板
  2. 定时发送:支持计划发送时间
  3. A/B测试:支持不同内容版本测试
  4. 统计分析:发送效果分析和报表
  5. 国际化:支持多语言消息模板

自定义扩展

开发者可以通过实现 EmailServiceSMSService 接口来扩展支持更多服务商:

interface EmailService {
  send(to: string, subject: string, content: string): Promise<SendResult>;
  sendBatch(recipients: EmailRecipient[]): Promise<BatchSendResult>;
}

通过工厂模式注册新的服务实现即可使用。