群發(Broadcast)與進線原因(InboundReason)規格說明書

版本: v1.0\ 最後更新: 2026-06-13\ 服務範圍: aile-service-tenant(核心)、aile-service-room(協同)


第一部分:群發(Broadcast)

1. 概述

群發(Broadcast)是 Aile 提供的批量消息推送能力,允許服務號向符合特定條件(標籤篩選或指定客戶列表)的客戶群發送訊息。群發支援定時發送、渠道過濾和結果統計。


2. BroadcastModel(群發持久化模型)

2.1 資料結構

MongoDB 集合:aile.tenant.servicenumber.broadcast


    
    
    
  // aile-api/aile-tenant-api/.../model/servicenumber/BroadcastModel.java
@Document("aile.tenant.servicenumber.broadcast")

@CompoundIndexes({
    @CompoundIndex(name = "serviceNumberId", def = "{'serviceNumberId': 1}"),
    @CompoundIndex(name = "serviceNumberId_1_status_1_updateTime_1", 
        def = "{'serviceNumberId': 1, 'status': 1, 'updateTime': 1}")
})

public
 class BroadcastModel extends BaseModel {
    String name;                   // 任務標題
    String remark;                 // 備註
    String tenantId;               // 租戶 ID
    String accountId;              // 操作者帳號 ID
    String memberId;               // 操作者客服 memberId
    String serviceNumberId;        // 服務號 ID
    Long broadcastTime;            // 預定發送時間
    List<String> labelIds;         // 目標標籤 ID 列表(選填)
    List<String> customerIds;      // 目標客戶 ID 列表(選填)
    LabelMatchLogic matchLogic;    // 標籤匹配邏輯(AND / OR)
    List<BroadcastBody> content;   // 群發內容
    BroadcastStatus status;        // 狀態
    Channel channel;               // 目標渠道
    Integer totalCount;            // 目標總數
    Integer successCount;          // 成功數
    Integer failCount;             // 失敗數
}

2.2 狀態機


    
    
    
  // aile-api/aile-tenant-api/.../enums/servicenumber/BroadcastStatus.java
public
 enum BroadcastStatus {
    Will,    // 待發送
    Doing,   // 發送中
    Done,    // 已完成
    Delete   // 已刪除
}

    
    
    
  Will ──→ Doing ──→ Done
  │                 │
  └──→ Delete       └──→ Delete

3. 群發服務實現

3.1 BroadcastServiceImpl

位置:aile-service/aile-service-tenant/.../service/servicenumber/impl/BroadcastServiceImpl.java

核心方法:

方法說明
create(dto)建立群發任務
update(dto)更新任務(僅 Will 狀態可更新)
start(broadcastId)啟動發送(Will → Doing)
complete(broadcastId)完成發送(Doing → Done)
delete(broadcastId)刪除任務(軟刪除)
list(dto)分頁查詢群發任務

3.2 目標受眾計算


    
    
    
  BroadcastServiceImpl.start()
  │
  ├── 若有 labelIds
  │     ├── 依 matchLogic(AND/OR)查詢符合標籤的客戶列表
  │     └── 交叉過濾 customerIds(如有指定)
  │
  ├── 若僅有 customerIds
  │     └── 直接使用指定客戶列表
  │
  ├── 渠道過濾
  │     └── 僅向指定 channel 的客戶發送
  │
  ├── 計算 totalCount = 目標客戶數
  │
  └── 逐個客戶發送消息
        ├── 成功 → successCount++
        └── 失敗 → failCount++(記錄日誌)

4. 消息發送機制

4.1 BroadcastMessageUtil

位置:aile-service/aile-service-room/.../message/BroadcastMessageUtil.java

群發消息透過 Room 服務發送:


    
    
    
  BroadcastServiceImpl
  │
  └── MessageFeign.sendServiceMessage(dto)  [跨服務調用]
        │
        └── aile-service-room
              │
              └── BroadcastMessageUtil.sendBroadcastMessage()
                    ├── 建立 MessageModel
                    ├── 寫入對應 Services Room
                    └── 透過 GatewayFeign 外發

4.2 廣播內容格式


    
    
    
  // BroadcastBody(內嵌於 BroadcastModel)
public
 class BroadcastBody {
    MessageType type;    // 消息類型(Text / Image / Template 等)
    String text;         // 文字內容
    String fileUrl;      // 媒體文件 URL
    // Template 消息

    TemplateMessage template; // 模板消息(包含 Action 按鈕等)
}

5. 群發 API

路由:/servicenumber/broadcast/

方法路徑說明
POST/broadcast/create建立群發任務
POST/broadcast/update更新群發任務
POST/broadcast/start啟動發送
POST/broadcast/complete標記完成
POST/broadcast/delete刪除任務
POST/broadcast/list查詢任務列表
GET/broadcast/detail?broadcastId=查詢任務詳情
POST/broadcast/target-batch批量查詢目標受眾

6. 定時發送

群發支援預約發送,透過 broadcastTime 欄位指定未來時間:


    
    
    
  BroadcastModel.broadcastTime
  │
  └── 定時任務掃描 (Cron / OnceScheduleManager)
        ├── 檢查 broadcastTime ≤ now
        ├── 檢查 status = Will
        └── 自動調用 start()

第二部分:進線原因(InboundReason)

7. 概述

進線原因(InboundReason)是 Aile 提供的客戶進線來源標記系統,用於追蹤客戶是從哪個業務場景進入客服對話的。支援兩種模式:

模式說明
預設來源(Preset)管理員預先配置的進線原因,客戶進線時透過 URL 參數或 API 指定
即時原因(RealTime)客戶進線時動態傳入的進線原因資料

8. ServiceInboundReasonModel(進線原因配置)

8.1 資料結構

MongoDB 集合:aile.tenant.inbound.reason


    
    
    
  // aile-api/aile-tenant-api/.../model/inboundreason/ServiceInboundReasonModel.java
@Document("aile.tenant.inbound.reason")

@CompoundIndexes({
    @CompoundIndex(name = "tenantId", def = "{'tenantId': 1}")
})

public
 class ServiceInboundReasonModel extends BaseModel {
    String tenantId;                          // 租戶 ID
    String sourceName;                        // 來源名稱(如「官網首頁」)
    ServiceInboundReasonTypeEnum sourceType;  // 來源類型
    String description;                       // 進線原因描述
    String businessId;                        // 業務 ID(關聯特定業務場景)
    Long validityPeriod;                      // 有效期(null 或 0 表示永久有效)
    Boolean status;                           // 啟用/禁用
}

8.2 進線原因類型枚舉


    
    
    
  // aile-api/aile-tenant-api/.../enums/ServiceInboundReasonTypeEnum.java
public
 enum ServiceInboundReasonTypeEnum {
    SCAN_QR_CODE("qrcode", "掃碼進線"),       // 門店、海報、線下活動
    PRODUCT_CONSULT("product", "商品咨詢"),    // 商品詳情頁、商品列表
    PROMOTION_CONSULT("activity", "活動咨詢"), // 促銷活動卡片、活動頁面
    SIGNATURE("signature", "簽名檔進線"),      // 員工郵件簽名檔連接
    CUSTOMER_SUPPORT("support", "客服支持"),   // 幫助中心、聯繫我們
    PRICING_CONSULT("pricing", "定價咨詢"),    // 定價頁面、價格表
    CUSTOM("custom", "自定義")                 // 業務自定義場景
}

9. ServiceInboundReasonSessionModel(進線原因-會話關聯)

9.1 資料結構

MongoDB 集合:aile.tenant.servicenumber.inbound.reason.session


    
    
    
  // aile-api/aile-tenant-api/.../model/inboundreason/ServiceInboundReasonSessionModel.java
@Document("aile.tenant.servicenumber.inbound.reason.session")

@CompoundIndexes({
    @CompoundIndex(name = "sourceId", def = "{'sourceId': 1}"),
    @CompoundIndex(name = "sessionId", def = "{'sessionId': 1}"),
    @CompoundIndex(name = "serviceNumberId_sourceId", def = "{'serviceNumberId': 1, 'sourceId': 1}"),
    @CompoundIndex(name = "serviceNumberId_sourceId_transferToAgent", 
        def = "{'serviceNumberId': 1, 'sourceId': 1, 'transferToAgent': 1}")
})

public
 class ServiceInboundReasonSessionModel extends BaseModel {
    String tenantId;                          // 租戶 ID
    String serviceNumberId;                   // 服務號 ID
    String sessionId;                         // 會話 ID
    String roomId;                            // 聊天室 ID
    String customerId;                        // 客戶 ID
    String sourceId;                          // 進線原因 ID(關聯 ServiceInboundReasonModel)
    Boolean transferToAgent;                  // 是否轉人工
    ServiceInboundReasonOrigin originType;    // 來源類型:Preset / RealTime
    String sourceData;                        // 即時原因資料(JSON 字串,originType=RealTime 時使用)
    String sourceName;                        // 來源名稱快照(建立關聯時的來源名稱)
    ServiceInboundReasonTypeEnum sourceType;  // 來源類型快照
}

10. 進線原因來源類型


    
    
    
  // aile-api/aile-tenant-api/.../enums/ServiceInboundReasonOrigin.java
public
 enum ServiceInboundReasonOrigin {
    Preset,   // 預設來源(管理員配置的進線原因)
    RealTime  // 即時原因(客戶進線時動態傳入)
}
類型說明使用場景
Preset預先配置好的進線原因掃碼進線、商品頁面進線、活動頁面進線
RealTime進線時動態指定的原因自定義業務場景、外部系統傳入的臨時原因

11. 進線原因服務

11.1 ServiceInboundReasonService

位置:aile-service/aile-service-tenant/.../service/inboundreason/ServiceInboundReasonService.java

提供進線原因配置的 CRUD:

方法說明
create(dto)建立進線原因配置
update(dto)更新配置
delete(id)刪除配置
list(dto)分頁查詢配置列表
enable(id) / disable(id)啟用/停用

11.2 ServiceInboundReasonSessionService

位置:aile-service/aile-service-tenant/.../service/inboundreason/ServiceInboundReasonSessionService.java

提供進線原因與會話的綁定:


    
    
    
  public interface ServiceInboundReasonSessionService extends BaseMongoService<ServiceInboundReasonSessionModel> {
    void
 bindSession(ServiceInboundReasonSessionBindDto bindDto);
    void
 markTransferToAgent(String sessionId);
}

12. 進線原因綁定流程


    
    
    
  客戶進線(攜帶進線原因參數)
  │
  ├── 透過 URL 參數 ?sourceId=xxx 指定預設原因
  │     或
  ├── 透過 API 傳入即時原因資料
  │
  └── ServiceInboundReasonServiceImpl
        │
        ├── 查詢 ServiceInboundReasonModel(若 sourceId 有效)
        ├── 建立 ServiceSession(會話)
        └── ServiceInboundReasonSessionService.bindSession(bindDto)
              │
              ├── 建立 ServiceInboundReasonSessionModel
              │     ├── originType = Preset(若使用預設原因)
              │     │            = RealTime(若動態傳入)
              │     ├── sourceName = 快照當前的來源名稱
              │     └── sourceData = 即時原因的 JSON 資料(RealTime 時)
              │
              └── 關聯 sessionId ↔ sourceId

13. 轉人工標記


    
    
    
  ServiceInboundReasonSessionService.markTransferToAgent(sessionId)
  │
  └── 更新 ServiceInboundReasonSessionModel.transferToAgent = true

此標記用於統計:哪些進線原因的客戶最終轉了人工客服。


14. 進線原因統計

基於 ServiceInboundReasonSessionModel 的聚合查詢:

統計維度說明
按來源類型各來源類型的進線量、轉人工量
按預設原因每個預設配置的進線量
按即時原因按 sourceName 分組的即時原因進線量
轉人工率transferToAgent=true 的比例

15. 進線原因 API

15.1 進線原因配置 API

路由:/inboundreason/

方法路徑說明
POST/inboundreason/create建立進線原因
POST/inboundreason/update更新進線原因
POST/inboundreason/delete刪除進線原因
POST/inboundreason/list查詢進線原因列表
GET/inboundreason/detail?inboundReasonId=查詢詳情

15.2 進線原因關聯查詢 API

方法路徑說明
GET/inboundreason/session/list?sessionId=查詢會話的進線原因
GET/inboundreason/session/statistics進線原因統計

16. 業務場景示例

16.1 掃碼進線


    
    
    
  1. 管理員配置進線原因:
   sourceName = "台北門市",sourceType = SCAN_QR_CODE
2. 生成帶參數的二維碼 URL:
   https://line.me/R/ti/p/@xxx?sourceId=INB_001
3. 客戶掃碼後進線:
   → 自動綁定 sourceId="INB_001"
   → originType=Preset
   → 記錄進線原因快照

16.2 即時原因


    
    
    
  1. 外部系統呼叫進線 API,附帶:
   { sourceName: "訂單 #12345 查詢", sourceType: "custom", sourceData: { orderId: "12345" } }
2. 系統建立進線原因關聯:
   → originType=RealTime
   → sourceData = {"orderId":"12345"}
   → 客服端顯示「進線原因:訂單 #12345 查詢」

17. 群發與進線原因的關聯

群發任務可以透過進線原因數據進行精準投放:


    
    
    
  BroadcastServiceImpl(選擇目標受眾時)
  │
  ├── 可選:篩選有特定進線原因的客戶
  │     ├── 查詢 ServiceInboundReasonSessionModel
  │     │     └── sourceId = "INB_001"(掃碼進線的客戶)
  │     └── 取得 customerId 列表
  │
  └── 將篩選結果作為群發目標

18. 關鍵檔案索引

群發(Broadcast)

層級檔案說明
API Modelaile-api/aile-tenant-api/.../model/servicenumber/BroadcastModel.java群發持久化模型
API Enumaile-api/aile-tenant-api/.../enums/servicenumber/BroadcastStatus.java群發狀態枚舉
Serviceaile-service/aile-service-tenant/.../service/servicenumber/impl/BroadcastServiceImpl.java群發服務實現
Room Utilaile-service/aile-service-room/.../message/BroadcastMessageUtil.java群發消息工具

進線原因(InboundReason)

層級檔案說明
API Modelaile-api/aile-tenant-api/.../model/inboundreason/ServiceInboundReasonModel.java進線原因配置模型
API Modelaile-api/aile-tenant-api/.../model/inboundreason/ServiceInboundReasonSessionModel.java進線原因-會話關聯模型
API Enumaile-api/aile-tenant-api/.../enums/ServiceInboundReasonTypeEnum.java進線原因類型枚舉
API Enumaile-api/aile-tenant-api/.../enums/ServiceInboundReasonOrigin.java來源類型枚舉
API DTOaile-api/aile-tenant-api/.../dto/inboundreason/ServiceInboundReasonSessionBindDto.java會話綁定 DTO
Serviceaile-service/aile-service-tenant/.../service/inboundreason/ServiceInboundReasonService.java進線原因服務接口
Serviceaile-service/aile-service-tenant/.../service/inboundreason/ServiceInboundReasonSessionService.java關聯服務接口
Service Implaile-service/aile-service-tenant/.../service/inboundreason/impl/ServiceInboundReasonServiceImpl.java進線原因服務實現
Service Implaile-service/aile-service-tenant/.../service/inboundreason/impl/ServiceInboundReasonSessionServiceImpl.java關聯服務實現
Redis Keyaile-api/aile-tenant-api/.../constant/ServiceInboundReasonRedisKey.java進線原因 Redis Key