Aile 帳號身份體系規格說明書

版本: v1.0\ 最後更新: 2026-06-13\ 服務範圍: aile-service-accountaile-service-tenantaile-service-room


1. 概述

Aile 的身份體系採用分層設計,以 Account(帳號) 為頂層統一身份,向下關聯 AppAccount(應用帳號)TenantEmployee(員工)TenantContact(客戶/聯繫人) 等租戶級身份。系統支援匿名訪客到實名用戶的平滑過渡,並透過 Scope 機制管理渠道級身份映射。

1.1 核心設計原則

原則說明
Account 是統一身份錨點所有租戶級身份(員工、客戶)都歸屬於一個 Account
租戶隔離同一 Account 在不同租戶中有獨立的 Employee 或 Contact 記錄
渠道多身份同一 Account 可透過多個 channel+scopeId 訪問同一服務號
匿名可合併匿名訪客的 Contact 資料可在實名登入後合併到實名 Account

2. 身份層級總覽


    
    
    
  ┌─────────────────────────────────────────────────────────┐
│                     AccountModel                         │
│              (aile.account) — 頂層統一身份                 │
│  欄位: mobile, channel, status, isSystem, personRoomId   │
│  類型: Anonymous | NonRealName | RealName | System       │
└────────────┬──────────────┬──────────────────────────────┘
             │              │
      ┌──────▼──────┐  ┌───▼──────────────────────────┐
      │ AppAccount  │  │     AccountScopeModel         │
      │ Model       │  │  (aile.account.scope)         │
      │ (aile.      │  │  帳號在渠道上的 scope 映射      │
      │  account    │  │  accountId ↔ channel ↔ scopeId│
      │  .app)      │  └───────────────────────────────┘
      │ 應用帳號     │
      └─────────────┘

┌──────────────────────────────────────────────────────────┐
│                    租戶層 (Tenant)                         │
│                                                          │
│  ┌─────────────────────┐  ┌────────────────────────────┐ │
│  │ TenantEmployeeModel │  │   TenantContactModel       │ │
│  │ (aile.tenant.       │  │  (aile.tenant.contact)     │ │
│  │  employee)          │  │  客戶 / 聯繫人               │ │
│  │ 員工                 │  │  type: RealName |          │ │
│  │ joinType: Guarantor  │  │         Anonymous |        │ │
│  │         | Invitation │  │         Independent       │ │
│  └─────────┬───────────┘  └─────────────┬──────────────┘ │
│            │                             │                │
└────────────┼─────────────────────────────┼────────────────┘
             │                             │
      ┌──────▼──────┐              ┌───────▼──────────────┐
      │ServiceMember│              │  ServiceNumberScope   │
      │   Model     │              │       Model           │
      │ 服務號成員   │              │  服務號進線 scope      │
      │ privilege:  │              │  customerId ↔         │
      │ Owner /     │              │  serviceNumberId ↔    │
      │ Manager /   │              │  channel ↔ scopeId    │
      │ Common      │              │  ↔ roomId             │
      └─────────────┘              └───────────────────────┘
                                           │
                                   ┌───────▼──────────────┐
                                   │ServiceNumberRelation  │
                                   │       Model           │
                                   │  服務號訂閱關係         │
                                   │  customerId ↔         │
                                   │  serviceNumberId ↔    │
                                   │  accountId            │
                                   └───────────────────────┘

3. AccountModel(頂層帳號)

3.1 資料結構

MongoDB 集合:aile.account


    
    
    
  // aile-api/aile-account-api/.../model/AccountModel.java
@Document("aile.account")

public
 class AccountModel extends BaseModel {
    String mobile;        // 手機號碼
    String countryCode;   // 國碼
    Channel channel;      // 註冊渠道
    Status status;        // Enable / Disable(Saga 歸併可標記為 Deleted)
    Boolean isSystem;     // 是否為系統帳號
    String personRoomId;  // 個人聊天室 ID(系統級)
}

3.2 帳號類型(推導)

帳號類型透過 AccountType.get(AccountModel) 推導,非持久化欄位:


    
    
    
  // aile-api/aile-account-api/.../enums/AccountType.java
public
 enum AccountType {
    Anonymous,    // 匿名用戶(Channel.isAnonymous() == true)
    NonRealName,  // 未實名用戶(無手機號)
    RealName,     // 實名用戶(有手機號)
    System        // 系統用戶(isSystem == true)
}

3.3 登入方式


    
    
    
  // aile-api/aile-account-api/.../constant/LoginType.java
LINE(1),         // LINE 登入
THIRD(2),        // 第三方登入
OTP(3),          // OTP 登入
PWD(4),          // 密碼登入
ONCE_TOKEN(5),   // 一次性 Token 登入
DEVICE(6),       // 裝置登入
QRCODE(7),       // 掃描登入
ACCESS(8),       // 授權登入
SERVICE(9),      // 服務登入
AUTO(10),        // 自動登入
ANONYMOUS(11)    // 匿名登入

3.4 帳號服務

位置:aile-service/aile-service-account/.../service/impl/AccountServiceImpl.java

方法說明
register(dto)註冊新帳號(手機號 + 渠道)
login(dto)登入(支援多種登入方式)
syncCreate(dto)同步建立(供跨服務調用)
update(dto)更新帳號資訊

4. AppAccountModel(應用帳號)

4.1 資料結構

MongoDB 集合:aile.account.app


    
    
    
  // aile-api/aile-account-api/.../model/AppAccountModel.java
@Document("aile.account.app")

@CompoundIndexes({
    @CompoundIndex(name = "accountId_1_channel_1", def = "{'accountId': 1, 'channel': 1}"),
    @CompoundIndex(name = "accountId_1_channel_1_status_1", def = "{'accountId': 1, 'channel': 1, 'status': 1}"),
    @CompoundIndex(name = "accountId_1_updateTime_1", def = "{'accountId': 1, 'updateTime': 1}")
})

public
 class AppAccountModel extends BaseModel {
    String accountId;      // 關聯的 Account ID
    String name;           // 顯示名稱
    Integer age;           // 年齡
    Gender gender;         // 性別
    String birthday;       // 生日
    List<String> interests;// 興趣標籤
    Channel channel;       // 渠道
    String password;       // 密碼(加密)
    String avatarId;       // 頭像 ID
    Status status;         // Enable / Disable
    Boolean androidMute;   // Android 靜音
    Boolean iosMute;       // iOS 靜音
    Boolean pcMute;        // PC 靜音
    // ...

}

4.2 設計意圖


5. AccountScopeModel(帳號渠道 Scope)

5.1 資料結構

MongoDB 集合:aile.account.scope


    
    
    
  // aile-api/aile-account-api/.../model/AccountScopeModel.java
@Document("aile.account.scope")

@CompoundIndexes({
    @CompoundIndex(name = "scopeId_1_channel_1", def = "{'scopeId': 1, 'channel': 1}"),
    @CompoundIndex(name = "accountId_1_channel_1_scopeId_1", def = "{'accountId': 1, 'channel': 1, 'scopeId': 1}")
})

public
 class AccountScopeModel extends BaseModel {
    String scopeId;    // 渠道側唯一 ID(如 LINE userId)
    Channel channel;   // 渠道
    String accountId;  // 關聯的 Account ID
    String name;       // 渠道側顯示名稱
}

5.2 用途

AccountScopeModel 是 Account 層級的渠道映射,與 Tenant 層級的 ServiceNumberScopeModel 互補:

層級模型用途
Account 層AccountScopeModelAccount ↔ channel ↔ scopeId(登入級)
Tenant 層ServiceNumberScopeModelContact ↔ serviceNumberId ↔ channel ↔ scopeId(服務號級)

6. TenantEmployeeModel(員工)

6.1 資料結構

MongoDB 集合:aile.tenant.employee


    
    
    
  // aile-api/aile-tenant-api/.../model/TenantEmployeeModel.java
@Document("aile.tenant.employee")

public
 class TenantEmployeeModel extends BaseModel {
    String name;                // 姓名
    String avatarId;            // 頭像 ID
    String mood;                // 個性簽名
    Integer age;                // 年齡
    Gender gender;              // 性別
    String birthday;            // 生日
    Status status;              // Enable / Disable
    String accountId;           // 關聯的 Account ID
    String tenantId;            // 所屬租戶 ID
    Channel channel;            // 渠道
    String personRoomId;        // 個人聊天室 ID
    String systemRoomId;        // 系統聊天室 ID
    TenantJoinType joinType;    // 加入方式:Guarantor / Invitation
    String openId;              // 外部 OpenID
    Boolean isJoinAile;         // 是否已加入 Aile 生態
    Boolean isBindAile;         // 是否已綁定 Aile 生態
    Boolean isCollectInfo;      // 是否已收集資訊
    String homePagePicId;       // 主頁背景圖 ID
}

6.2 加入方式


    
    
    
  // aile-api/aile-tenant-api/.../enums/TenantJoinType.java
public
 enum TenantJoinType {
    Guarantor,   // 擔保人邀請
    Invitation   // 邀請碼加入
}

6.3 與 Account 的關係

6.4 加入生態流程


    
    
    
  Account 登入
  │
  └── TenantBindService.send(TenantBindDto)
        │
        ├── 向 Account 的個人聊天室發送「加入生態」卡片
        ├── Account 接受 → TenantBindService.collectInfo()
        │     ├── 建立 TenantEmployeeModel
        │     ├── isJoinAile = true
        │     └── isBindAile = true
        │
        └── TenantBindService.check()
              └── 檢查 Account 是否已加入該租戶

7. TenantContactModel(客戶 / 聯繫人)

7.1 資料結構

MongoDB 集合:aile.tenant.contact


    
    
    
  // aile-api/aile-tenant-api/.../model/TenantContactModel.java
@Document("aile.tenant.contact")

public
 class TenantContactModel extends BaseModel {
    // 基本資料

    String name;                // 姓名
    Integer age;
    Gender gender;
    String birthday;
    String phone;
    String email;
    // 公司資料

    String company;
    Boolean isAileCompany;
    String companyAddress;
    String companyPhone;
    String companyEmail;
    String companyDuty;
    String companyDepartment;
    // 其他

    BloodType bloodType;
    MaritalStatus maritalStatus;
    List<Language> languages;
    String interests;
    String alias;              // 備註名
    String description;        // 描述
    String businessCardId;     // 名片 ID
    String openId;             // 外部 OpenID
    String avatarId;           // 頭像 ID
    // 關聯

    Status status;
    String accountId;          // 關聯的 Account ID
    String tenantId;           // 所屬租戶 ID
    Channel channel;           // 渠道
    Boolean isJoinAile;        // 是否已加入 Aile
    Boolean isBindAile;        // 是否已綁定
    Boolean isCollectInfo;     // 是否已收集資訊
    // 類型

    ContactType type;           // RealName / Anonymous / Independent
}

7.2 客戶類型


    
    
    
  // aile-api/aile-tenant-api/.../enums/contact/ContactType.java
public
 enum ContactType {
    RealName,     // 實名會員(關聯了 Account)
    Anonymous,    // 匿名會員(未關聯 Account,僅有渠道 scopeId)
    Independent   // 獨立客戶(如 LineGroup 帶入的客戶,不屬於任何 Account)
}

7.3 關鍵規則


8. ServiceMemberModel(服務號成員)

8.1 資料結構

MongoDB 集合:aile.tenant.servicenumber.member


    
    
    
  // aile-api/aile-tenant-api/.../model/servicenumber/ServiceMemberModel.java
@Document("aile.tenant.servicenumber.member")

public
 class ServiceMemberModel extends BaseModel {
    String serviceNumberId;            // 服務號 ID
    String memberId;                   // 成員 ID(即 TenantEmployeeModel.id)
    String accountId;                  // 關聯 Account
    String tenantId;                   // 租戶 ID
    ServiceNumberType serviceNumberType; // 服務號類型
    ServiceMemberPrivilege privilege;  // Owner / Manager / Common
    Status status;                     // Enable / Disable
}

8.2 權限層級


    
    
    
  // aile-api/aile-tenant-api/.../enums/ServiceMemberPrivilege.java
public
 enum ServiceMemberPrivilege {
    Owner,    // 擁有者
    Manager,  // 管理員
    Common    // 一般成員
}

8.3 關係鏈


    
    
    
  Account ──→ TenantEmployee ──→ ServiceMember
                                 │
                                 ├── serviceNumberId
                                 └── privilege (Owner / Manager / Common)

一個員工可以同時是多個服務號的成員,每個服務號中有獨立的權限。


9. ServiceNumberScopeModel(服務號進線 Scope)

9.1 資料結構

MongoDB 集合:aile.tenant.servicenumber.scope


    
    
    
  // aile-api/aile-tenant-api/.../model/servicenumber/ServiceNumberScopeModel.java
@Document("aile.tenant.servicenumber.scope")

public
 class ServiceNumberScopeModel extends BaseModel {
    String tenantId;         // 租戶 ID
    String accountId;        // 帳號 ID
    String customerId;       // 客戶 ID(TenantContactModel.id)
    Channel channel;         // 渠道
    String scopeId;          // 渠道側唯一 ID(如 LINE userId 或 chat.code)
    String serviceNumberId;  // 服務號 ID
    String code;             // 渠道側主體 code
    String name;             // 渠道側顯示名稱
    String avatarId;         // 頭像 ID
    String pictureUrl;       // 頭像 URL
    String roomId;           // 對應的 Services Room ID
    Status status;           // Enable / Disable
}

9.2 核心作用

ServiceNumberScopeModel 是系統中最關鍵的橋接模型:


    
    
    
  客戶 ──→ ServiceNumberScopeModel ──→ 服務號
  │            │                        │
  │     ┌──────┴──────────┐             │
  │     │ customerId      │             │
  │     │ serviceNumberId │             │
  │     │ channel         │             │
  │     │ scopeId         │             │
  │     │ roomId          │             │
  │     └─────────────────┘             │
  │                                     │
  └── TenantContactModel ───────────────┘

一個客戶可以在同一服務號下有多條 Scope 記錄(不同 channel),但同一 channel + scopeId + serviceNumberId 組合唯一。


10. ServiceNumberRelationModel(服務號訂閱關係)

10.1 資料結構

MongoDB 集合:aile.tenant.servicenumber.relation


    
    
    
  // aile-api/aile-tenant-api/.../model/servicenumber/ServiceNumberRelationModel.java
@Document("aile.tenant.servicenumber.relation")

public
 class ServiceNumberRelationModel extends BaseModel {
    String serviceNumberId;
    ServiceNumberType serviceNumberType;
    String accountId;        // 帳號 ID
    String customerId;       // 客戶 ID
    String tenantId;         // 租戶 ID
    String roomId;           // 聊天室 ID
    ServiceOpenType openType;// 公開類型
    ServiceNumberRelationStatus status; // 訂閱狀態
    String alias;            // 備註名
}

10.2 與 Scope 的區別

模型用途粒度
ServiceNumberScopeModel渠道進線路由(實際收發消息)channel + scopeId + serviceNumberId
ServiceNumberRelationModel業務層訂閱/關注關係customerId + serviceNumberId

11. 匿名訪客與實名合併

11.1 匿名訪客的產生


    
    
    
  1. 用戶透過 LINE 匿名進入
   → Gateway Webhook 事件
   → 若無對應 Account:建立 AccountModel(type=Anonymous)
   → 建立 TenantContactModel(type=Anonymous)
   → 建立 ServiceNumberScopeModel
   → 建立 ServiceNumberRelationModel

11.2 匿名訪客 ContactType 標記


    
    
    
  // TenantContactModel.type 可為:
ContactType.Anonymous     // 匿名訪客,未關聯實名 Account
ContactType.RealName      // 實名客戶,關聯了實名 Account
ContactType.Independent   // 獨立客戶(如 LineGroup 帶入,不經過 Account)

11.3 實名登入合併流程

當匿名訪客進行實名登入(如輸入手機號)時:


    
    
    
  AnonymousVisitorMergePlanAdapter.resolve(anonymousAccountId, targetAccountId)
  │
  ├── 查詢 anonymousAccountId 下的所有 TenantContactModel(status=Enable)
  │
  ├── 逐個客戶生成 ContactMergePlan:
  │     ├── 查找目標 Account 在該租戶是否已有 Contact(targetContact)
  │     ├── 收集匿名客戶的 ServiceNumberRelation 列表
  │     ├── 收集目標客戶的 ServiceNumberRelation 列表
  │     └── 生成合併計劃(標記源客戶刪除、遷移關聯)
  │
  └── Saga 編排執行:
        ├── MergeAnonymousVisitorContactDataStep(合併客戶資料)
        ├── ProcessServiceSessionMergeStep(合併會話)
        ├── MergeLineGroupContactRelationStep(合併 LineGroup 關聯)
        └── 其他相關 Step

11.4 Saga 步驟清單

Step說明
ResolveContactMergePlanStep解析合併計劃
MergeAnonymousVisitorContactDataStep合併匿名訪客客戶資料
ProcessServiceSessionMergeStep合併會話記錄
MergeLineGroupContactRelationStep合併 LineGroup 關聯
MarkSourceServiceSessionDeletedStep標記源會話刪除
GatewayCustomerDeleteStep通知 Gateway 清理舊客戶

12. 房間成員類型


    
    
    
  // aile-api/aile-room-api/.../enums/RoomMemberType.java
public
 enum RoomMemberType {
    User,           // 一般用戶(員工或客戶)
    ServiceNumber,  // 服務號
    Robot,          // 機器人
    Assistant,      // AI 助手
    Room            // 聊天室本身(系統消息)
}
成員類型對應實體說明
UserTenantEmployeeModelTenantContactModel房間中的人類成員
ServiceNumberServiceNumberModel服務號作為房間成員
Robot機器人帳號自動回覆機器人
AssistantTenantAssistantModelAI 助手

13. 完整關係圖


    
    
    
                            ┌──────────────────┐
                          │   AccountModel   │
                          │  (aile.account)  │
                          │  mobile, channel │
                          │  status, isSystem│
                          └───┬──────┬───────┘
                              │      │
              ┌───────────────┘      └───────────────┐
              ▼                                      ▼
   ┌──────────────────┐                  ┌──────────────────────┐
   │  AppAccountModel │                  │  AccountScopeModel   │
   │ (aile.account.   │                  │  (aile.account.      │
   │  app)            │                  │  scope)              │
   │  name, avatar    │                  │  channel, scopeId    │
   │  channel, mute   │                  └──────────────────────┘
   └──────────────────┘

              │ accountId
              │
   ┌──────────┴─────────────────────────────────────┐
   │                   Tenant (租戶)                  │
   │                                                  │
   │  ┌──────────────────────┐  ┌──────────────────┐ │
   │  │ TenantEmployeeModel  │  │TenantContactModel│ │
   │  │ (aile.tenant.        │  │(aile.tenant.     │ │
   │  │  employee)           │  │ contact)         │ │
   │  │ id → memberId        │  │ id → customerId  │ │
   │  └─────────┬────────────┘  └────────┬─────────┘ │
   │            │                        │           │
   └────────────┼────────────────────────┼───────────┘
                │                        │
         ┌──────▼──────┐          ┌──────▼───────────────┐
         │ServiceMember│          │ServiceNumberScopeModel│
         │   Model     │          │ (aile.tenant.         │
         │ memberId    │          │  servicenumber.scope) │
         │ privilege   │          │ customerId            │
         │ (Owner /    │          │ serviceNumberId       │
         │  Manager /  │          │ channel ↔ scopeId     │
         │  Common)    │          │ roomId                │
         └─────────────┘          └──────────┬────────────┘
                                             │
                                    ┌────────▼────────────┐
                                    │ServiceNumberRelation │
                                    │       Model          │
                                    │ (aile.tenant.        │
                                    │  servicenumber.      │
                                    │  relation)           │
                                    │ customerId           │
                                    │ serviceNumberId      │
                                    │ accountId            │
                                    │ status               │
                                    └──────────────────────┘

14. 關鍵身份流轉場景

14.1 新用戶首次進線


    
    
    
  LINE 用戶掃碼進入服務號
  │
  ├── 無 Account → 建立 Anonymous Account
  ├── 無 TenantContact → 建立 Contact(type=Anonymous)
  ├── 建立 ServiceNumberScope(customerId + serviceNumberId + channel + scopeId)
  ├── 建立 ServiceNumberRelation(customerId + serviceNumberId + accountId)
  └── 建立 Services Room → 開始會話

14.2 匿名轉實名


    
    
    
  Anonymous Account 輸入手機號進行實名登入
  │
  ├── Account 升級:type: Anonymous → RealName(填入手機號)
  ├── 觸發 Saga:AnonymousVisitorMergePlanAdapter
  │     ├── 查找該 Account 的所有 Anonymous Contact
  │     ├── 對每個 Contact 生成合併計劃
  │     └── Saga 編排執行(合併 Contact、合併 Session、合併 Relation)
  └── Contact 升級:type: Anonymous → RealName

14.3 已有 Account 進線新租戶


    
    
    
  已實名 Account 透過 LINE 進入新租戶的服務號
  │
  ├── 查找 Account(依 channel + scopeId → AccountScope)
  ├── 在該租戶建立 TenantContactModel(type=RealName)
  ├── 建立 ServiceNumberScope
  └── 建立 ServiceNumberRelation

14.4 員工加入生態


    
    
    
  用戶登入 → 通過邀請/擔保加入租戶
  │
  ├── 若無 Account → 建立 Account
  ├── 建立 TenantEmployeeModel(joinType=Guarantor/Invitation)
  ├── TenantBindService.send() → 發送加入生態卡片
  ├── 用戶接受 → isJoinAile=true, isBindAile=true
  └── 可被加入 ServiceMember(成為服務號客服)

14.5 LineGroup 獨立客戶


    
    
    
  LINE 群組事件(MemberJoin / Messaging)
  │
  ├── 群組成員可能沒有 Account
  ├── 建立 TenantContactModel(type=Independent)
  │     └── Independent:不關聯 Account,僅作為群組內的用戶身份
  ├── 建立 LineGroupContactRelationModel
  └── 加入 LineGroup Room 為成員

15. 關鍵檔案索引

層級檔案說明
API Modelaile-api/aile-account-api/.../model/AccountModel.java頂層帳號
API Modelaile-api/aile-account-api/.../model/AppAccountModel.java應用帳號
API Modelaile-api/aile-account-api/.../model/AccountScopeModel.java帳號渠道 Scope
API Enumaile-api/aile-account-api/.../enums/AccountType.java帳號類型(Anonymous/NonRealName/RealName/System)
API Constaile-api/aile-account-api/.../constant/LoginType.java11 種登入方式
API Modelaile-api/aile-tenant-api/.../model/TenantEmployeeModel.java員工
API Modelaile-api/aile-tenant-api/.../model/TenantContactModel.java客戶/聯繫人
API Enumaile-api/aile-tenant-api/.../enums/contact/ContactType.java客戶類型(RealName/Anonymous/Independent)
API Enumaile-api/aile-tenant-api/.../enums/TenantJoinType.java加入方式
API Modelaile-api/aile-tenant-api/.../model/servicenumber/ServiceMemberModel.java服務號成員
API Enumaile-api/aile-tenant-api/.../enums/ServiceMemberPrivilege.java服務號權限
API Modelaile-api/aile-tenant-api/.../model/servicenumber/ServiceNumberScopeModel.java服務號進線 Scope
API Modelaile-api/aile-tenant-api/.../model/servicenumber/ServiceNumberRelationModel.java服務號訂閱
API Enumaile-api/aile-room-api/.../enums/RoomMemberType.java房間成員類型
API Enumaile-api/aile-job-api/.../enums/UserTypeEnums.java用戶類型(Employee/Contact/Visitor)
Serviceaile-service/aile-service-account/.../service/impl/AccountServiceImpl.java帳號服務
Serviceaile-service/aile-service-tenant/.../service/impl/TenantBindServiceImpl.java租戶綁定服務
Mergeaile-service/aile-service-tenant/.../merge/adapter/AnonymousVisitorMergePlanAdapter.java匿名訪客合併
Sagaaile-service/aile-service-tenant/.../saga/step/MergeAnonymousVisitorContactDataStep.javaSaga 合併步驟
Sagaaile-service/aile-service-tenant/.../saga/step/ResolveContactMergePlanStep.java合併計劃解析