跳至主要内容

LineGroup 規格說明書

項目名稱: Aile
範圍: Gateway Line 群組事件 → tenant → room(lineGroup)
最後更新: 2026-06-13
版本: v2.0 — 結合代碼實現的完整規格


1. 概述

LineGroup 是 Aile 針對 LINE 渠道「群組聊天」場景設計的專用聊天室類型。與私聊 services 聊天室不同,LineGroup 以群為單位管理 LINE 群組內的成員、消息和外發路由。

1.1 設計目標

目標說明
一個群一個房一個 serviceNumberId + chat.code 只對應一個啟用中的 lineGroup 聊天室
真實發言人群消息顯示真實發言人頭像/暱稱,不是「群本身」
群級路由對外回發消息只向群發一次,不按成員逐個外發
持久化關係持久化群成員與聊天室的關係,支援成員展示與歸屬追蹤

1.2 非目標

  • 不創建 ServiceSession(不走客服會話流程)
  • 不走機器人歡迎語、自動接待、會話超時分配邏輯
  • 不要求機器人入群前回補歷史群成員

2. 資料模型

2.1 聊天室類型

// aile-api/aile-room-api/.../constant/RoomType.java
public static final String LineGroup = "lineGroup";

RoomModel 中的關鍵字段(用於 LineGroup):

字段來源說明
type固定 "lineGroup"聊天室類型標識
serviceNumberIdwebhook.to.code歸屬服務號
namewebhook.chat.name群組名稱
avatarwebhook.chat.pictureUrl群組頭像
externalRoomIdwebhook.chat.codeLINE 群組唯一 ID
channel"Line"來源渠道

2.2 LineGroupContactRelationModel

MongoDB 集合:aile.tenant.contact.linegroup.relation

此模型記錄「LINE 群組 ↔ 客戶(聯繫人)」的多對多關聯。

// aile-api/aile-tenant-api/.../model/servicenumber/LineGroupContactRelationModel.java
@Document("aile.tenant.contact.linegroup.relation")
@CompoundIndexes({
@CompoundIndex(name = "serviceNumberId_1_lineGroupId_1_scopeId_1",
def = "{'serviceNumberId': 1, 'lineGroupId': 1, 'scopeId': 1}"),
@CompoundIndex(name = "roomId_1_status_1", def = "{'roomId': 1, 'status': 1}"),
@CompoundIndex(name = "contactId_1_status_1", def = "{'contactId': 1, 'status': 1}"),
@CompoundIndex(name = "tenantId_1_lineGroupId_1_status_1",
def = "{'tenantId': 1, 'lineGroupId': 1, 'status': 1}")
})
public class LineGroupContactRelationModel extends BaseModel {
String tenantId; // 租戶 ID
String serviceNumberId; // 服務號 ID
String lineGroupId; // LINE 群組 ID(即 chat.code)
String roomId; // Aile 聊天室 ID
String scopeId; // LINE 用戶 scopeId(即 sender.code)
String contactId; // Aile 聯繫人 ID
String status; // 狀態(Enable / Disable)
}

3. 核心服務與實現

3.1 LineGroupRoomImpl(聊天室工廠策略)

位置:aile-service/aile-service-room/.../factory/strategy/impl/LineGroupRoomImpl.java

繼承 CommonRoomImpl,覆寫關鍵方法以適應群組場景:

方法行為
checkMessage()識別系統帳號消息,設置發送人名稱
createRoom()基於 LineGroupRoomCreateDto 建立聊天室
消息分發roomMessageDispatchBatchWorkerExecutor 批量分發

3.2 Gateway 事件處理(tenant 服務)

位置:aile-service/aile-service-tenant/.../gateway/factory/strategy/impl/

事件實現類處理邏輯
JoinAbstractEventImpl (共用)建立/恢復群級 scope + lineGroup 聊天室
LeaveAbstractEventImpl (共用)停用 lineGroup + 群級 scope + 外部成員關係
MemberJoinMemberJoinEventImpl建立聯繫人 + 成員級 scope + 房間成員
MemberLeaveMemberLeaveEventImpl停用房間成員關係
MessagingMessagingEventImpl懶建立群/成員 → 寫入消息

3.3 LineGroupContactRelationService

位置:aile-service/aile-service-tenant/.../service/servicenumber/

提供 Line 群組與客戶關聯的 CRUD 及查詢能力:

public interface LineGroupContactRelationService extends BaseMongoService<LineGroupContactRelationModel> {
// 依 lineGroupId + scopeId 查找關聯
// 依 roomId 查詢成員列表
// 批量啟用/停用關聯
}

對應 Controller:LineGroupContactRelationController(路由:/servicenumber/linegroup-contact-relation

3.4 Saga 整合

在租戶資料歸戶/清理流程中,LineGroup 關聯資料也納入 Saga 步驟:

  • MergeLineGroupContactRelationStep:合併 LineGroup 聯繫人關聯
  • MergeAnonymousVisitorContactDataStep:合併匿名訪客資料(包含 LineGroup 關聯)

4. 事件處理完整流程

4.1 Join(LINE OA 被拉入群)

Gateway ──→ aile-service-tenant (GatewayController)

├── 解析 webhook:提取 chat.code、chat.name、chat.pictureUrl、to.code

├── 建立/恢復群級 scope
│ scopeId = chat.code
│ code = from.code
│ channel = Line
│ serviceNumberId = to.code

├── 建立/恢復 lineGroup 聊天室(透過 RoomFeign 呼叫 room 服務)
│ type = lineGroup
│ serviceNumberId = to.code
│ externalRoomId = chat.code
│ name = chat.name
│ avatar = chat.pictureUrl

└── 加入服務號為房間成員

4.2 MemberJoin(新成員加入)

Gateway ──→ aile-service-tenant

├── 解析 members[]:提取每個 member 的 code、name、pictureUrl

├── 確保群級 scope 和 lineGroup 存在(不存在則補建)

└── 對每個 member:
├── 建立/更新 TenantContactModel(聯繫人資料)
├── 建立/更新成員級 scope(scopeId = member.code)
├── 建立 LineGroupContactRelationModel
└── 加入 lineGroup 房間成員

4.3 Messaging(群消息)

Gateway ──→ aile-service-tenant ──→ aile-service-room

├── 確保群級 scope 和 lineGroup 存在

├── 依 sender.code 懶建立聯繫人/成員級 scope/房間成員
│ (若此前未收到 MemberJoin)

├── 消息寫入 lineGroup 聊天室
│ senderId = 實際成員聯繫人 ID(非 chat.code)
│ senderName = 聯繫人名稱

└── 不創建 ServiceSession,不走機器人流程

4.4 Leave(LINE OA 被移出群)

Gateway ──→ aile-service-tenant

├── 停用 lineGroup 聊天室(軟刪除)
├── 停用群級 scope
└── 批量停用房間成員關係

5. 發送規則詳解

5.1 群級路由

LINE 群組消息外發使用 群級 scopescopeId = chat.code),而非成員級 scope。

對外發送目標:scopeId = chat.code
路由方式:GatewayFeign → Gateway 群級路由
發送次數:一條內部消息 → 一次外部發送

5.2 發送者展示

展示元素取值來源
senderId實際成員對應的聯繫人 ID
senderName成員聯繫人名稱
senderAvatar成員聯繫人頭像

禁止使用 chat.code 或群級 scope 作為消息發送者。

5.3 與 Services Room 的關鍵差異

維度Services RoomLineGroup Room
會話模型每客戶一個 ServiceSession無 ServiceSession
外發目標成員級 scope(單個客戶)群級 scope(整個群)
機器人流程支援(歡迎語/自動接待/超時)不支援
消息發送者客戶本人群內實際發言人
房間類型serviceslineGroup

6. 冪等性與一致性

  • 同一 serviceNumberId + chat.code 只允許一個啟用中的 lineGroup
  • 同一成員在同一 lineGroup 中只允許一條啟用中的成員關係
  • 事件亂序時採取「補建優先、刪除冪等」策略
  • 處理順序:先保證群級資料 → 再保證成員級資料 → 最後寫入消息

7. 關鍵檔案索引

層級檔案說明
API Modelaile-api/aile-room-api/.../constant/RoomType.javaLineGroup 常量
API Modelaile-api/aile-room-api/.../dto/room/LineGroupRoomCreateDto.java建立聊天室 DTO
API Modelaile-api/aile-room-api/.../dto/room/LineGroupRoomInfoSyncDto.java群資訊同步 DTO
API Modelaile-api/aile-room-api/.../dto/room/LineGroupRoomListDto.java列表查詢 DTO
API Modelaile-api/aile-tenant-api/.../model/servicenumber/LineGroupContactRelationModel.java群客戶關聯
API Modelaile-api/aile-tenant-api/.../dto/servicenumber/LineGroupContactRelationListDto.java關聯查詢 DTO
Room 服務aile-service/aile-service-room/.../factory/strategy/impl/LineGroupRoomImpl.java群組聊天室策略
Room 服務aile-service/aile-service-room/.../util/LineGroupUnreadWrite.java未讀數寫入
Room 服務aile-service/aile-service-room/.../util/LineGroupMemberRoomRedisUtil.java成員房間 Redis
Room 服務aile-service/aile-service-room/.../util/LineGroupMemberUnread.java成員未讀
Tenant 服務aile-service/aile-service-tenant/.../gateway/factory/strategy/impl/MemberJoinEventImpl.javaMemberJoin 事件
Tenant 服務aile-service/aile-service-tenant/.../gateway/factory/strategy/impl/MemberLeaveEventImpl.javaMemberLeave 事件
Tenant 服務aile-service/aile-service-tenant/.../service/servicenumber/impl/LineGroupContactRelationServiceImpl.java關聯服務實現
Tenant 服務aile-service/aile-service-tenant/.../controller/servicenumber/LineGroupContactRelationController.java關聯 API
Sagaaile-service/aile-service-tenant/.../saga/step/MergeLineGroupContactRelationStep.javaSaga 合併步驟

8. 驗收條件

功能驗收

  • Join 到達後建立 lineGroup 聊天室,服務號自動加入為成員
  • 聊天室資料可查到 LINE 群組 chat.code
  • MemberJoin 到達後為新成員建立聯繫人、scope 和房間成員關係
  • Messaging 到達後群消息進入 lineGroup,展示真實發送者
  • MemberLeave 到達後停用成員關係,保留聯繫人資料
  • Leave 到達後停用 lineGroup,保留歷史消息
  • 從 lineGroup 回發消息只向群組發送一次

資料驗收

  • 群級路由和成員級身份可區分查詢
  • 群級外部 ID 與成員級 scopeId 不混用
  • 同一 LINE 用戶可出現在多個 lineGroup 中,聯繫人不重複

Changelog

日期版本變更內容
2026-03-27v1.0初始 Line 群組聊天室細規格
2026-06-13v2.0結合代碼實現補充完整規格(資料模型、服務實現、事件流程、檔案索引)