---
doc_id: aireach-three-piece-architecture
title: AiReach 三件套架構設計方案（開發參考）
description: AiReach 自建 Backend、Node BFF、React 前端與 Aile/AIFF/AileAI 整合邊界的三件套架構方案，供開發團隊參考。
slug: /developers/aireach-three-piece-architecture
product: AiReach
category: development-reference
audience:
  - developer
  - architect
visibility: public
status: published
version: 1.3.0
owner: aile-platform
updated_at: 2026-06-12
tags:
  - AiReach
  - AiPower
  - AIFF
  - 開發參考
rendered_html: /rendered/developers/aireach-three-piece-architecture/
download: true
sidebar_position: 3
---

# AiReach — AiPower 單元 + Node BFF + React 前端三件套設計方案 v1.3

<aside>
📣

**方案核心要點 (v1.3)**

- **三層架構**:Aile(多租戶客服 / 通訊底座) → AiReach(**自建獨立 Backend 服務** + Node BFF + React 前端,Aile 生態下首個 CRM 營銷應用);**v1.5 起不再基於 AiPower 平臺開發**(詳 §〇)。
- **AS = Aile 生態統一認證服務**(獨立服務,專司 SSO / Token 簽發與校驗),**並非**`aile-service-*` 套件簡稱。
- **AiReach 本期三件套**:
    1. **業務後端** = **AiReach Backend Service(獨立服務,新建,Java / Node 自選)**:自有 DB + 業務邏輯 + 排程 + 多租戶隔離 + `event_inbox` 冪等 + `tenant_integration` 金鑰 + Tool API
    2. **BFF(Node.js,新建)**:前端聚合(含前端聚合所需的 Aile 出站呼叫) + AS SSO + Aile 整合**入站**協議(install / webhook) + 與 Backend 整合(含 `tenant_integration` 同步) + **發起 AIFF 配置註冊**;**不參與業務後端出站簽名**
    3. **前端(React,新建)**:**一份獨立 React Web**;同一份部署同時滿足獨立訪問與 AileDesktop 多個 AIFF 槽位嵌入
- **AIFF 是 Aile 側前端開發框架**:透過 `POST /openapi/v1/aiff/**`(spec v1.0 §9.2)註冊「**嵌入位置 + endpoint URL**」,AileDesktop 在對應位置載入 endpoint 並注入上下文(token / serviceNumberId / contactId 等)。
- **Aile 整合身份**:僅 AiReach 獨立註冊為 IntegrationApp `aireach`;**簽名 / install / webhook 由 BFF 承接**;BFF 驗籤後將 `eventId` 透傳給 AiReach Backend,**冪等去重由 Backend 的 `event_inbox` 單元負責**。
- **活動作用域**:服務號級,campaign 必填 `serviceNumberId`;contact_profile 三元主鍵 `(tenantId, serviceNumberId, aileContactId)`。
- **MVP 推播鏈路**:複用 Aile 現行**服務號群發**能力;**Aile 不維護通知模板**,AiReach 按 `NoticeContent` 契約自行組合;需 Aile 側補齊 9 項 OpenAPI + 3 項 webhook 事件 = 12 項;**F 類「進線原因聯動」** 為可選擴充套件,可按 campaign / action 選用(§四)。
- **AiReach 標籤體系自治(v1.3.9)**:AiReach 營銷標籤由 **AiPower 業務單元**(`tag` / `tag_assignment` / `smart_tag_rule`)自管;Aile 側 D 類標籤介面保留**僅供其他 IntegrationApp 使用**,AiReach 受眾一律以 A1 `audience.type="contacts"` 形態提交(詳 §4.7);超 1000 拆多個 A1 子任務以 `parentTaskId` 關聯,Aile 不感知。
- **AI 編排域 = AileAI(v1.4 新增,Phase 2)**:Copilot 對話編排、多 Agent / skills、RAG 知識檢索與流式輸出由 **AileAI** 承接;**AiReach Backend 是資料與統計/工具域**(把業務資料能力工具化為 Tool API 供 AileAI 呼叫);BFF 在原職責上增加 **SSE 中繼 + 薄 AI 閘道器**;Aile 底座保持零侵入(不為 AI 新增 OpenAPI)。詳見 §2.4 四方全景與 AiReach Phase 2 — AI 能力完整設計方案 v0.2。
</aside>

> [!NOTE]
> 本文件定位為開發參考用的臨時設計稿，協助團隊在正式規格文件發布前對齊架構邊界；待正式規格建立後，可由正式文件取代並移除此參考稿。

---

## 〇、架構方向變更(v1.5):AiReach 自建獨立 Backend

<aside>
⚠️

**核心決策反轉(取代此前的 AiPower 口徑)**:AiReach **不再基於 AiPower 平臺建制單元 / 流程**,改為**自建獨立的 AiReach Backend Service**(技術棧 Java / Node 自選)。原由 AiPower 承載的業務主資料、`event_inbox` 冪等、`tenant_integration` 金鑰、排程、多租戶隔離、Tool API,全部下沉進 AiReach Backend Service 自有邊界。BFF、AileAI、Aile / AS、前端 / AIFF 的職責不變。

</aside>

### 〇.1 調整後的整體架構

```mermaid
flowchart TB
	subgraph USER["使用方"]
		AD["AileDesktop · AIFF 槽位"]
		BR["瀏覽器 · 獨立 Web"]
	end
	subgraph FE["AiReach 前端 · 一份 React Web"]
		Console["營銷控制檯 /app · /embed"]
		Copilot["Copilot 抽屜 / AI Studio"]
	end
	subgraph BFF["AiReach BFF · Node.js · 協議 + 聚合 + AI 閘道器"]
		SSO["AS SSO / Session / RBAC"]
		Proto["Aile 入站協議<br>install · webhook · AIFF 註冊"]
		Agg["前端聚合 + Backend Client"]
		TISync["tenant_integration 同步"]
		AiGw["薄 AI 閘道器 + SSE 中繼"]
	end
	subgraph BE["AiReach Backend Service · 獨立 · 新建"]
		Biz["業務邏輯<br>campaign · audience · tag* · broadcast"]
		Inbox["event_inbox 冪等"]
		TI["tenant_integration 金鑰"]
		Sched["排程 / 任務佇列 / 多租戶隔離"]
		DB[("自有 DB")]
		ToolApi["Tool API<br>query_metrics · draft_campaign · dispatch_campaign ..."]
	end
	subgraph AILEAI["AileAI · AI 編排域"]
		Agents["Copilot Router / 多 Agent"]
		Skills["skills · RAG · MCP"]
	end
	subgraph AILE["Aile 底座"]
		AS["AS 統一認證服務 · 獨立"]
		GW["Aile 閘道器 · platform-integration"]
		MSG["message 群發 / 點選捕獲"]
		WH["獨立 Webhook 服務"]
	end
	AD --> Console
	BR --> Console
	Console --> Agg
	Copilot --> AiGw
	Agg --> Biz
	AiGw --> Agents
	SSO -->|OAuth / Token| AS
	Proto --> GW
	WH -->|EventEnvelope| Proto
	Proto -->|eventId 透傳| Inbox
	TISync -.install / rotate 同步.-> TI
	Agents -->|ToolUse 取數| ToolApi
	ToolApi --> Biz
	Agents --> Skills
	Biz --> DB
	Inbox --> DB
	Biz -->|業務出站 · 讀 TI 簽名直髮| GW
	GW --> MSG
```

### 〇.2 職責搬遷對照

| 維度 | 原口徑(基於 AiPower) | 調整後(獨立 Backend) |
| --- | --- | --- |
| 業務後端 | AiPower 單元 + 流程,不寫微服務 | **AiReach Backend Service(獨立服務,新建)** |
| 業務主資料 | AiPower 單元表 | **Backend 自有 DB** |
| `event_inbox` 冪等 | AiPower 平臺單元 | **Backend** |
| `tenant_integration` 金鑰 | BFF → AiPower 平臺單元 | **BFF → Backend** |
| 業務出站簽名 | AiPower 單元直髮 Aile 閘道器 | **Backend 讀 TI 直髮 Aile 閘道器** |
| Tool API(供 AileAI) | AiPower 把資料能力工具化 | **Backend 暴露 Tool API** |
| 排程 / 多租戶 / 欄位建模 | AiPower 平臺能力 | **Backend 自建** |

> **權衡**:AiPower 原本白送的「快速建制單元 / 流程、排程、多租戶隔離、欄位建模、AI SDK」自建後需自行選型實現,初期成本與維護量上升;換得技術棧自由與不受平臺節奏約束。
> 

### 〇.3 全域性口徑替換(適用於下文 §一~§九)

下文多數章節成稿於 AiPower 口徑,在後續版本逐節落地前,按以下規則換算:

- 「AiPower 單元 / 流程 / 業務單元」→「AiReach Backend Service」
- 「AiPower 平臺單元 `event_inbox` / `tenant_integration`」→「Backend 內的 `event_inbox` / `tenant_integration`」
- 「AiPower OpenAPI」→「Backend API」
- 「資料與統計 / 工具域」由 AiReach Backend 承載
- 「業務出站簽名」由 Backend 讀 `tenant_integration` 直髮 Aile 閘道器
- BFF、AileAI、Aile / AS、前端 / AIFF 的職責不變

---

## 一、命名與定位

| 層級 | 實體 | 角色定位 | 本期形態 |
| --- | --- | --- | --- |
| 底座層 | **Aile** | 多租戶客服 / 通訊底座;裡面包含:`AS`(生態統一認證服務,獨立)與 `aile-service-*` 業務服務套件(auth / platform-integration / message / tenant / room / account / job ...)。**AS 與 `aile-service-*` 是兩個並列概念**,不是同物。 | 不變 |
| 平臺層 | **AiPower** | **Java 開發平臺**:提供單元(Unit)與流程(Flow)的快速建制、欄位建模、事件掛鉤、排程、AI 能力、賬號體系、多租戶隔離等能力 | **v1.5 起不採用**;相關能力改由 AiReach Backend 自建 |
| 業務層 | **AiReach** | **應用層概念**。本期實現物 = AiReach Backend Service(獨立) + BFF(Node.js) + React 前端 | 獨立註冊為 Aile IntegrationApp `aireach` |
| AI 編排層 | **AileAI** | **AI 編排域**(Phase 2 引入):Copilot 對話編排、多 Agent / skills、RAG 知識檢索、MCP 聯結器與流式輸出;經 Backend Tool API 取結構化資料,經 RAG / MCP 取知識規範 | Phase 2 接入;MVP 不啟用 |

### 1.1 AiReach 應用三件套

| 元件 | 形態 | 技術棧 | 主要職責 | 本期是否新建 |
| --- | --- | --- | --- | --- |
| **業務後端** | 獨立部署的 AiReach Backend Service | Java / Node(自選) | 領域建模 + 業務流程 + **`event_inbox` 單元**(冪等去重) + AI 能力經 AileAI 編排 | **新建**(獨立服務) |
| **BFF** | 獨立部署的 Node.js 服務 | Node.js + TypeScript | 1) 前端聚合:把 AiPower 多個單元的資料聚合為 UI 所需檢視
2) **走 AS 完成 SSO** / Token 校驗
3) **Aile 整合入站協議**:`/install` `/update` `/uninstall` `/rotate-secret`;**webhook 接收驗籤**(**不**承擔業務後端的出站簽名)
4) 與 Backend 整合:**install / rotate-secret 時把 `tenant_integration` 同步到 AiPower 平臺單元**  • 入站事件**透傳 eventId**  • 規範化命令下發
5) **AIFF 配置註冊**:在 install 後呼叫 `/openapi/v1/aiff/**` 註冊槽位 + endpoint
6) **前端聚合出站呼叫**:模板 / 預覽 / 受眾查詢 / 標籤等 UI 觸發的 Aile 呼叫由 BFF 本地簽名代發 | **新建** |
| **前端** | **一份獨立 React Web**(不另打 AIFF 包) | React + TypeScript | 營銷運營控制檯 UI;**同一份部署**同時供獨立 Web 與多個 AIFF 槽位(以不同 `endpoint URL` 路由區分) 呼叫 | **新建** |

### 1.2 AiReach 與 Aile 的接入身份表

| 欄位 | 取值 |
| --- | --- |
| Aile 側 `integrationAppId` | `aireach` |
| Aile 側註冊者 | Aile 平臺管理員一次性 `POST /admin/integrations/apps` |
| `installBaseUrl` | **AiReach BFF 暴露**的 HTTPS 安裝入口 |
| `tenantIntegrationId` / `tenantIntegrationSecret` | 每個 Aile 租戶安裝時生成;**BFF 本地 `tenant_integration` 表落檔** |
| `webhookUrl` | **BFF 匯出**的單一 webhook 接收地址(業務事件 + `notice.*` 合併端點) |
| SSO | **BFF 走 AS**(Aile 統一認證服務)完成 OAuth / Token 校驗 |
| AIFF 嵌入 | **BFF 發起呼叫** `POST /openapi/v1/aiff/**` 註冊「槽位 + endpoint URL」 |
| 安裝 / webhook 是否經 AiPower | **否**。入站協議在 BFF;BFF 以「內部呼叫」下發給 AiPower 單元(並同步 `tenant_integration` 到 AiPower 平臺單元) |
| 業務出站簽名是否在 BFF | **否**。**AiPower 單元 / 流程**從本地 `tenant_integration` 平臺單元讀取 Secret 後**直接**簽名呼叫 Aile 閘道器;BFF 僅承擔前端聚合出站 + install / AIFF 註冊的簽名 |

### 1.3 關鍵邊界

- Aile 側本期只看到一條 `aireach` IntegrationApp;**入站契約動作**(install / webhook / AIFF 註冊)在 **BFF**;**業務後端出站簽名呼叫** AiPower 單元 / 流程**直接**對 Aile 閘道器發起(BFF 不在業務出站鏈路上)。
- **AiPower 業務單元不感知 Aile 簽名 / 協議細節**,只接收 BFF 傳入的「規範化事件 / 命令 + eventId」與發起「規範化出站請求」;**冪等去重由 AiPower `event_inbox` 單元完成**。
- **BFF 同時是前端聚合層與 Aile↔AiPower 之間的協議橋**。
- **前端只部署一份 React Web**;AileDesktop 中的嵌入由在 AS 側註冊的 AIFF 配置驅動,不需要另打 AIFF 包。

---

## 二、架構總覽

### 2.1 整體部署拓撲

```mermaid
flowchart TB
	subgraph User["使用方"]
		AD["AileDesktop 桌面端"]
		BR["瀏覽器(獨立 Web)"]
	end

	subgraph FE["AiReach 前端 (一份 React Web)"]
		WebRoot["獨立訪問路由 /app/*"]
		EmbedRoot["AIFF 槽位路由 /embed/*"]
	end

	subgraph BFFLayer["AiReach BFF (Node.js)"]
		BFFApi["BFF REST / GraphQL API"]
		SSO["AS SSO 適配"]
		ProtoLayer["Aile 整合入站協議<br>(install / webhook)"]
		AiffReg["AIFF 配置註冊器"]
		AipowerProxy["AiPower 整合層"]
	end

	subgraph AiPower["AiPower 開發平臺 (Java)"]
		Units["AiReach 業務單元<br>Campaign / Audience / Dispatch / Profile / event_inbox"]
		Flows["AiReach 流程編排"]
		AipowerOpenApi["AiPower OpenAPI"]
		AiSDK["AiPower AI 能力"]
		Sched["AiPower 排程"]
	end

	subgraph Aile["Aile 多租戶客服底座"]
		AS["AS<br>(Aile 統一認證服務)"]
		PI["aile-service-platform-integration<br>(/openapi/v1/* 閘道器)"]
		AuthSrv["aile-service-auth<br>(含 AIFF 資源域)"]
		MsgSrv["aile-service-message"]
		OtherSrv["aile-service-tenant / room / account / job ..."]
		WHSrv["獨立 Webhook 服務"]
	end

	AD -->|按 AIFF 配置載入 endpoint URL| EmbedRoot
	BR -->|訪問域名| WebRoot
	WebRoot --> BFFApi
	EmbedRoot --> BFFApi

	BFFApi --> SSO
	BFFApi --> AipowerProxy
	SSO -->|OAuth / Token 校驗| AS
	AipowerProxy -->|HTTPS| AipowerOpenApi
	AipowerOpenApi --> Units
	AipowerOpenApi --> Flows
	Flows -.->|呼叫| AiSDK
	Flows -.->|呼叫| Sched

	ProtoLayer -->|前端聚合出站簽名| PI
	AiffReg -->|/openapi/v1/aiff/**| PI
	Units -->|業務後端直髮簽名出站| PI
	ProtoLayer -.->|install/rotate 時<br>tenant_integration 同步| Units
	PI --> AuthSrv
	PI --> MsgSrv
	PI --> OtherSrv
	PI -->|/install /update /uninstall| ProtoLayer
	WHSrv -->|EventEnvelope| ProtoLayer
	ProtoLayer -->|eventId + 規範化命令| AipowerProxy
```

### 2.2 各元件職責與部署要點

| 元件 | 部署單元 | 對外介面 | 儲存 | 執行身份 |
| --- | --- | --- | --- | --- |
| **前端** | 一份 React Web。獨立訪問走 `/app/*`;AileDesktop 嵌入走 `/embed/*` | 向 BFF 發起 REST / GraphQL | 無(程序記憶體 + IndexedDB 可選) | 兩種入口均使用 BFF 返回的會話身份 |
| **BFF** | 獨立 Node.js 服務 | 對前端:REST / GraphQL
對 Aile:1) 走 **AS** 完成 SSO / Token 校驗;2) 接收 PI 下發的 `/install` 與 Webhook;3) 經 **Aile 閘道器**以 AILE 簽名呼叫各 `aile-service-*` OpenAPI(含 `/openapi/v1/aiff/**` 註冊)
對 AiPower:HTTPS OpenAPI | **僅協議層狀態**:`tenant_integration` 、nonce / token / SSO session 快取(**不再持有 `event_inbox`**) | 以 `tenantIntegrationId` / Aile 租戶身份作上下文 |
| **AiPower 業務單元 + 流程** | 執行於 AiPower 平臺執行時,不獨立部署 | 對 BFF:AiPower OpenAPI(單元讀寫 + 流程觸發) | **業務主資料 + `event_inbox`冪等**:campaign / audience / dispatch / contact_profile / opt_out_ledger / conversion_log / **event_inbox**等均以單元表儲存 | AiPower 租戶上下文(與 Aile 租戶對映) |

### 2.3 前端兩種開啟方式

同一份 React 程式碼,只是入口路由不同。

| 維度 | 獨立 Web(`/app/*`) | AIFF 槽位(`/embed/*`) |
| --- | --- | --- |
| 入口 | 獨立域名 `aireach.<corp>.com` | AS 側註冊的 AIFF 配置中 `endpoint URL` 指向同一部署的 `/embed/*` 路由 |
| 登入態 | BFF 重定向走 **AS** SSO,後返 Cookie 會話 | AIFF 框架注入 Aile token / 上下文,BFF 校驗後建會話 |
| 上下文 | UI / URL 傳遞 | AIFF 框架以 URL 引數 / bridge 注入 `tenantId` `serviceNumberId` `contactId` 等 |
| 外殼 | 頂欄 + 側欄 | 隱藏頂欄 / 側欄,複用 AileDesktop 外殼 |
| 服務號選擇 | UI 切換器 | 預設跟隨 AileDesktop 當前服務號 |
| 除錯 | 瀏覽器 DevTools | AileDesktop AIFF DevTools(若提供) |

兩種開啟方式都走**同一個 BFF 域 + 同一份 React 部署**。

### 2.4 四方全景架構(含 AileAI,Phase 2 引入)

> MVP 階段不含 AileAI;下圖為引入 Phase 2 AI 能力後的目標全景。核心口徑:**AiPower = 資料與統計/工具域**,**AileAI = AI 編排域**,二者職責解耦;Aile / AS 底座零侵入(不為 AI 新增 OpenAPI)。
> 

```mermaid
flowchart TB
	subgraph USER["使用方"]
		AD["AileDesktop<br>(含 AIFF 槽位)"]
		BR["瀏覽器<br>(獨立 Web)"]
	end
	subgraph FE["AiReach 前端 (一份 React Web)"]
		Console["營銷控制檯<br>/app/* · /embed/*"]
		CopilotUI["AiReach Copilot 抽屜"]
		StudioUI["AI Content Studio / Segment / Insight"]
	end
	subgraph BFF["AiReach BFF (Node.js)"]
		Auth["AS SSO / Session / RBAC"]
		Agg["前端聚合 + AiPower Client"]
		Proto["Aile 入站協議<br>install / webhook + AIFF 註冊"]
		Sse["SSE 中繼 (Copilot 流式)"]
		AiGw["薄 AI 閘道器 /api/ai/*"]
	end
	subgraph AIP["AiPower (資料與統計/工具域 · Java 平臺)"]
		Units["業務單元<br>campaign / audience / broadcast_task<br>click_attribution / tag* / event_inbox / tenant_integration"]
		Flows["AI Flows<br>resolve_audience / generate_content / summarize_campaign"]
		Tools["Tool API<br>query_metrics / draft_campaign / dispatch_campaign ..."]
	end
	subgraph AILEAI["AileAI (AI 編排域)"]
		Router["Copilot Router 意圖分發"]
		Agents["多 Agent / ToolUse loop"]
		Skills["skills 提示詞 / 防注入 / schema 校驗"]
		RAG["Knowledge QA / RAG (租戶隔離)"]
		MCP["MCP Notion / Confluence / Drive / GitHub"]
	end
	subgraph AILE["Aile (多租戶客服 / 通訊底座)"]
		AS["AS 統一認證服務 (獨立)"]
		PI["Aile 閘道器<br>aile-service-platform-integration"]
		MSG["aile-service-message<br>服務號群發 / 點選捕獲"]
		ES["進線原因服務<br>EntrySource / Session"]
		WH["獨立 Webhook 服務"]
	end
	AD --> Console
	BR --> Console
	Console --> Agg
	CopilotUI --> Sse
	StudioUI --> AiGw
	Agg --> Units
	AiGw --> Flows
	Sse --> Agents
	Auth -->|OAuth / Token| AS
	Proto --> PI
	Proto -.install/rotate 同步.-> Units
	WH -->|EventEnvelope| Proto
	Agents -->|ToolUse| Tools
	Tools --> Units
	Agents --> RAG
	RAG --> MCP
	Units -->|業務後端直髮簽名| PI
	PI --> MSG
	PI --> ES
	Flows -.LLM 用量回傳.-> Units
```

**職責邊界(四方 + AS)**:

- **Aile / AS**:多租戶客服底座 + 統一認證;群發、點選捕獲、進線、SSO 全部沿用現行能力。
- **AiPower(資料與統計/工具域)**:業務主資料 + 統計聚合 + 把資料能力工具化為 **Tool API**(`query_metrics` / `draft_campaign` / `dispatch_campaign` / `resolve_audience` ...);強制 `tenantId` / `actor` 校驗與審計。
- **AileAI(AI 編排域)**:Copilot Router / 多 Agent / skills / RAG / MCP;**不直接拼 SQL、不越權**,只能經 AiPower Tool API 取數,經 RAG / MCP 取知識。
- **BFF**:在三件套原職責上增加 **SSE 中繼**(Copilot 流式)與 **薄 AI 閘道器**(`/api/ai/*`),不承載 AI 業務邏輯。
- **前端**:新增 **Copilot 抽屜** + **AI Content Studio / Segment / Insight** 入口,複用同一份 React 部署。

---

## 三、Aile 整合職責分配(協議層在 BFF)

Aile 與 AiReach 的整合按 spec v1.0 「**註冊 → 安裝握手 → 事件分發 + OpenAPI 呼叫**」四段實現,**協議層統一交 BFF**。

### 3.1 第一段:註冊 IntegrationApp(一次性)

Aile 平臺管理員一次性 `POST /admin/integrations/apps` 註冊 IntegrationApp:`appId=aireach` / `installBaseUrl` 指向 AiReach BFF / `supportedEvents` 訂閱 spec v1.0 八類資源域。

### 3.2 第二段:安裝握手 + AIFF 註冊

```mermaid
sequenceDiagram
	participant Admin as "Aile 租戶管理員"
	participant Console as "Aile 管理控制檯"
	participant PI as "aile-service-platform-integration<br>(平臺整合服務 + Aile 閘道器)"
	participant BFF as "AiReach BFF"
	participant AIP as "AiPower OpenAPI"
	participant AIFF as "aile-service-auth (AIFF 資源域)"

	Note over Admin,AIP: 第 1 段:安裝握手——PI 在此擴充「平臺整合服務」角色(主流程,Admin 阻塞等待)
	Admin->>Console: 啟用 AiReach
	Console->>PI: POST /admin/.../tenant-integrations
	PI->>PI: 建立 PENDING TenantIntegration<br>生成 tenantIntegrationId / Secret
	PI->>BFF: 簽名 POST {installBaseUrl}/install
	BFF->>BFF: 驗籤 + 落 tenant_integration
	BFF->>AIP: 建立 / 檢查 AiReach 租戶上下文<br>初始化 event_inbox 等業務單元
	AIP-->>BFF: 初始化完成 (externalTenantId)
	BFF-->>PI: 200 OK<br>{ webhookUrl(BFF 域), externalTenantId, installStatus=ACTIVE }
	PI->>PI: 寫 TenantMapping<br>TenantIntegration → ACTIVE
	PI-->>Console: 安裝完成
	Console-->>Admin: 安裝完成 (主流程結束)

	Note over BFF,AIFF: 第 2 段:AIFF 配置註冊——PI 在此擴充「OpenAPI 閘道器」角色(BFF 主動發起,非同步)
	BFF->>PI: 簽名 POST /openapi/v1/aiff/configurations<br>批次註冊該租戶 AIFF 槽位 + endpoint URL
	PI->>AIFF: 路由至 AIFF 資源域
	AIFF->>AIFF: 持久化 slot ↔ endpoint 配置
	AIFF-->>PI: 註冊成功
	PI-->>BFF: 200 OK
```

**BFF 處理要點**:

- 個人租戶共享 `externalTenantId = aireach_public_tenant`,以 `ownerId = ailePersonalTenantId` 隔離;團隊租戶為每 Aile 租戶在 AiPower 側建一個租戶上下文。
- 不僅初始化業務單元空間,還初始化 **`event_inbox` 單元**(主鍵 `(tenantIntegrationId, eventId)` 唯一)。
- `webhookUrl` 始終指向 BFF 域。
- 安裝後由 BFF **主動註冊 AIFF**(詳 §六),同時允許後期呼叫 PI 介面修改。
- `/update` `/uninstall` `/rotate-secret` 同樣由 BFF 接收。

### 3.3 第三段:事件分發(Aile → BFF → AiPower)

```mermaid
sequenceDiagram
	participant WH as "Aile 獨立 Webhook 服務"
	participant BFF as "AiReach BFF"
	participant AIP as "AiPower OpenAPI"
	participant Inbox as "event_inbox 單元(AiPower)"
	participant Flow as "AiPower 業務流程"

	WH->>BFF: POST /webhook + EventEnvelope + AILE 簽名
	BFF->>BFF: 驗籤 + nonce 檢查
	BFF->>BFF: 按 eventType 路由為「規範化命令」<br>(透傳 eventId)
	BFF->>AIP: 下發到 AiPower 入站介面<br>(攜帶 eventId)
	AIP->>Inbox: INSERT(eventId) ON CONFLICT DO NOTHING
	alt 首次看到
		AIP->>Flow: 起動業務流程
	else 重複事件
		AIP->>AIP: 丟棄
	end
	BFF-->>WH: 200 OK
```

**事件路由原則**:BFF 按 `eventType` 把 EventEnvelope 規範化為 AiPower 入站命令並下發;**冪等去重統一由 AiPower `event_inbox` 單元承擔**(`UNIQUE(tenantIntegrationId, eventId)` 衝突即跳過),BFF 僅做驗籤 + nonce 檢查 + 透傳 eventId。

### 3.4 第四段:OpenAPI 出站(AiPower → Aile 閘道器)

> **架構變更**:業務後端(AiPower 單元 / 流程)**直接**對 Aile 閘道器發起簽名呼叫,**不再經過 BFF**。BFF 僅承接 install / webhook / AIFF 註冊等協議入口動作,不充當業務出站代理 —— BFF 本質是 AiReach 前端的聚合層,後端不會主動呼叫 BFF。
> 

```mermaid
sequenceDiagram
	participant Unit as "AiPower 業務單元 / 流程"
	participant TI as "tenant_integration 平臺單元<br>(AiPower 內,BFF install 時同步落檔)"
	participant Gateway as "Aile 閘道器<br>(aile-service-platform-integration)"
	participant DS as "aile-service-* 領域服務"

	Note over Unit,DS: 業務後端 → Aile 直連,BFF 不在出站鏈路上
	Unit->>TI: 讀取該租戶 tenantIntegrationId / Secret
	TI-->>Unit: 返回憑據
	Unit->>Unit: 生成 nonce + bodyString<br>HmacSHA256 簽名
	Unit->>Gateway: HTTPS + Authorization: AILE <id>:<sig>
	Gateway->>DS: 路由到對應領域服務
	DS-->>Gateway: 響應
	Gateway-->>Unit: 響應
```

**簽名原子** (與 v1.2 一致):

```jsx
Authorization: AILE <tenantIntegrationId>:<signature>
raw = tenantIntegrationId + nonce + bodyString
signature = Base64(HmacSHA256(tenantIntegrationSecret, raw))
```

### 3.5 BFF 與 AiPower 的整合協議

| 環節 | 機制 |
| --- | --- |
| **`tenant_integration` 同步** | **BFF 在 install / rotate-secret 時,把 `tenantIntegrationId`  • `tenantIntegrationSecret`  • `webhookUrl` 同步落檔到 AiPower 的 `tenant_integration` 平臺單元**(同租戶上下文);供 AiPower 業務流程**直接**簽名出站呼叫 Aile 閘道器 |
| **SSO 上下文** | BFF 拿到經 **AS** 校驗的 Aile token 後,按「租戶對映表」兌換出 AiPower 側租戶 + 服務賬號 token |
| **單元訪問** | BFF 透過 AiPower OpenAPI 讀寫單元(含 `event_inbox`),不直接依賴 AiPower 內部儲存 |
| **流程觸發** | BFF 透過 AiPower OpenAPI 觸發流程,傳入入參 + eventId |
| **冪等保證** | BFF **不做本地去重**,僅透傳 eventId;AiPower 在 `event_inbox` 單元上 `UNIQUE(tenantIntegrationId, eventId)` 索引保證冪等 |

---

## 四、Aile 側為推播場景需補齊的介面清單(MVP)

AiReach 複用 Aile 現行**服務號群發**能力(已支援「按客戶標籤篩選 → 最多 5 則訊息 → 立即/定時」,本方案在 OpenAPI 層將 `audience` 欄位擴為 union 形態以支援「名單直傳」承載 AiReach 側已算出的精準受眾)作為推播主鏈;本方案在其上補齊 OpenAPI,讓 AiReach 業務後端可直接驅動群發任務,無需自行實現排程 / 受眾 / 渠道適配。NoticeContent 契約(§4.0)與點選 webhook(§4.4)承載卡片訊息與 Postback 歸因;進線原因聯動(§4.9)為可選擴充套件。

本章共 **9 項 OpenAPI + 3 項 webhook 事件 = 12 項**,服務號級介面落入字首 `/openapi/v1/service-numbers/&#123;snId&#125;/*`,租戶級進線原因介面落入字首 `/openapi/v1/entry-sources/*`,按資源域分別由 `aile-service-message` / 進線原因服務承載。

> **發起方約定**:群發任務 建立 / 查詢 / 取消 由 **AiReach Backend Service 直髮 Aile 閘道器**;客戶標籤 列表 / 打標 / 摘標 由 **BFF 前端聚合**(也可 AiPower 側發起)。
> 

> **MVP 範圍**:合規預檢(原 B 類)、轉化主動回寫(原 C 類)、推播額度、渲染預覽、AI / 高階受眾(原 E 類)本期不實現,後續按業務需要再補齊(章節已刪除,不再保留佔位)。
> 

### 4.0 NoticeContent 訊息格式契約

AiReach 傳送時直接按 Aile 真實 `NoticeContent` + `Action` 結構組合訊息體,隨 A1 群發任務的 `messages[]` 提交(詳 §4.1);Aile 僅做**結構校驗 + 內容安全檢測 + 渠道適配 + 點選捕獲回傳**,不維護模板態,不解析 `data` 欄位的業務語義(除 Postback 必須能解出頂層 `appId` 與 `event` 用於路由 / 分支 webhook 外)。

**`NoticeContent` 結構(對齊 Aile 現行卡片模型)**:

- `type` (string,固定 `"Buttons"`)
- `title` (string)
- `text` / `describe` (string,卡片正文)
- `image` (url,可選)
- `actions` (array, 0..N) —— 每項為 Aile `Action` 物件

**`Action` 欄位(Aile Java 模型)**:

| 欄位 | 型別 | 說明 |
| --- | --- | --- |
| `type` | `ActionType` | 必填。本方案僅使用 `Postback` / `Url` 兩類(Aile 真實列舉另含 `Aiff` / `Action` 等本地行為型別,屬 AIFF 嵌入觸發 / 匿名歸戶等內部場景,本方案不涉及) |
| `label` | string | 必填。按鈕顯示文字 |
| `data` | string (JSON) | 條件必填。**`type=Postback` 必填**,由 AiReach 自定義 JSON,Aile 不解析其餘欄位(`Postback` 必須能解出頂層 `appId` / `event`),webhook 原樣透傳 |
| `url` | string | 條件必填。**僅 `type=Url` 時必填** |
| `title` | string | 可選。行為標題,本方案可不填 |
| `text` | string | 可選。補充說明 |
| `imageUrl` | string | 可選。按鈕圖示 / 縮圖 |
| `displayText` | string | 可選。點選後客戶端顯示文字 |
| `isDefault` | boolean | 可選。是否預設動作 |

**`ActionType` 語義與點選處理(本方案使用範圍)**:

| type | 語義 | 必填欄位 | Aile 側點選處理 |
| --- | --- | --- | --- |
| `Postback` | 後端動作:客戶端回撥 Aile 後端,Aile 透傳給應用 | `label`  • `data`(JSON,**頂層必須包含 `appId` 欄位標記觸發應用**,其餘 schema 由 AiReach 自定) | 客戶端 → Aile postback 端點 → Aile 讀 `data.appId` 路由 webhook → 原樣發 `notice.clicked` 給該 integration |
| `Url` | 前端動作:跳轉外鏈網頁 | `label`  • `url` | 客戶端走 Aile 跳轉包裝(`/notice-click/&#123;noticeId&#125;/&#123;actionIndex&#125;` → 302 到目標)記錄點選 → 發 `notice.clicked` |

**`Action.data` 的歸屬與點選歸因**:

- **`data`** 在 `type=Postback`  下用作業務引數 JSON 字串:Aile **不解析**(除 `Postback` 必須能解出頂層 `appId` 用於路由 webhook 外),webhook 原樣透傳;AiReach 自定義業務 schema(歸因 id / 活動 ID / 業務欄位)。
- **點選歸因載體**:
    - `type=Postback`(**本方案主用**):`data` 頂層必含 Aile 保留欄位 `appId` + `event`(取值 `"Broadcast"` 群發 / `"InboundReason"` 進線原因聯動,詳 §4.9);AiReach 在其下自定業務欄位(例 `taskId` / `campaignId` / `bizEventCode` / `couponId`)
    - `type=Url`:Aile 僅以 `(noticeId, actionIndex)` 標識被點選的按鈕回傳

**示例 —— `type=Postback` + `type=Url` 混合卡片(AiReach 營銷活動典型形態)**:

```json
{
  "type": "Buttons",
  "title": "限时优惠券",
  "text": "点击领取你的专属券,有效期 24 小时。",
  "image": "https://cdn.aireach/.../coupon.png",
  "actions": [
    {
      "type": "Postback",
      "label": "立即领取",
      "data": "{\"appId\":\"aireach\",\"event\":\"Broadcast\",\"campaignId\":\"cmp_42\",\"bizEventCode\":\"REDEEM_COUPON\",\"couponId\":\"C123\"}"
    },
    {
      "type": "Url",
      "label": "查看详情",
      "url": "https://aireach.example.com/coupon/C123"
    }
  ]
}
```

**Postback `data` 健壯性約定**:

- `data` 解析失敗 → AiReach 視為無效點選,記錄錯誤日誌並丟棄,不影響 `notice.clicked` 事件落庫。
- `data` 缺少頂層 `appId` 或 `event` 欄位 → Aile 傳送時拒絕(詳 §4.8.2)。

**契約面小結(應用 ↔ Aile)**:

- AiReach 擁有 `Action.data` 的業務 schema 解釋權(本方案僅適用於 `Postback` 型別)。
- Aile 僅承擔:結構校驗 + Postback 路由(讀 `data.appId`) + 點選回傳 + 渠道適配。
- 不需要 Aile 提供「模板列表 / 模板詳情」介面。
- **Postback 強約定**:`data` 必須為合法 JSON 字串且頂層包含 **兩個 Aile 保留欄位**:`appId`(固定 `"aireach"`,Aile 據此路由 webhook 接收方)與 `event`(取值 `"Broadcast"` 或 `"InboundReason"`,Aile 據此判別處理流程,詳 §4.9;對齊 Aile 現行 `event:"InboundReason"` 既定格式);缺失任一則傳送時拒絕。

### 4.1 A 類——群發任務介面(複用 Aile 現行服務號群發,3 項)

對齊 Aile 管理後臺「新建群發任務」UI 欄位(任務名 / 備註 / 傳送渠道 / 1..5 則訊息 / 客戶標籤篩選 / 立即或定時):AiReach 透過 OpenAPI 一次性提交任務,Aile 按現行群發流程完成命中計算、排程、渠道適配與投遞。

| 代號 | 優先順序 | 方法 + 路徑 | 描述 | 發起方 |
| --- | --- | --- | --- | --- |
| **A1** | **P0** | `POST /openapi/v1/service-numbers/&#123;snId&#125;/broadcasts` | **建立群發任務** —— body:`name` / `note` / `channels[]`(預設 / LINE / Facebook / Instagram / ...) / `messages[]`(1..5 項,每項為 NoticeContent 卡片或 `&#123;type:"text"/"image"/"file", ...&#125;`) / `audience`(**二選一形態**:`&#123;type:"tags", tagIds[], tagOperator:"AND"|"OR"&#125;` 標籤篩選 = **Aile 側標籤**,保留供其他 IntegrationApp 使用,**AiReach 不消費此模式**;或 `&#123;type:"contacts", contactIds[]&#125;` 名單直傳,**AiReach 永遠走此模式**,單任務上限 **1000**,超限拆分詳 §4.7) / `schedule`(`&#123;type:"immediate"&#125;` 或 `&#123;type:"scheduled", at:"ISO 時間"&#125;`)。Aile 按現行群發流程命中、排程、投遞。返回 `taskId` / `estimatedRecipientCount` | Backend 直髮 |
| **A2** | **P0** | `GET /openapi/v1/service-numbers/&#123;snId&#125;/broadcasts/&#123;taskId&#125;` | **查詢群發任務狀態** —— 返回 `taskId` / `status`(`scheduled` / `sending` / `completed` / `cancelled` / `failed`) / `recipientCount` / `summary&#123;sent,delivered,failed,read&#125;` / `startedAt` / `finishedAt`。MVP 階段以輪詢替代任務級 webhook | Backend 直髮 |
| A3 | P1 | `POST /openapi/v1/service-numbers/&#123;snId&#125;/broadcasts/&#123;taskId&#125;:cancel` | **取消群發任務** —— 僅在 `scheduled` 狀態下有效 | Backend 直髮 |

**Aile 側需配套支援**:

1. 群發任務儲存與排程引擎已具備,本期僅追加 OpenAPI 入口。
2. `messages[]` 允許混合 文字 / 圖片 / 附件 / NoticeContent 卡片,最多 5 則,與 Aile UI 上限一致。
3. 卡片 Action 為 `Postback` 時,Aile 按 §4.5 鏈路捕獲點選併發 `notice.clicked`,事件 payload 需攜帶 `taskId` 用於 AiReach 關聯回任務。
4. 任務建立時按 `audience.type` 分支校驗:`tags` 模式校驗 `tagIds[]` 在該服務號下存在且非刪除態;`contacts` 模式校驗 `contactIds[]` 在該服務號下存在、單任務上限 **1000**(超限直接拒絕),系統自動去重並過濾退訂客戶。
5. 任務執行受 Aile 現行 退訂 / 頻次 / 時間窗 治理保護,被治理攔截的客戶不計入投遞成功。
6. 安全 / 內容稽核沿用 Aile 現行群發流水線。
7. 需追加客戶標籤列表 OpenAPI(詳 §4.5 D1)。
8. Aile 需識別新增 Postback `data.event="Broadcast"`(對齊現行 `event:"InboundReason"` 既定格式),路由 `notice.clicked` webhook 時無需建立 Session;`event` 欄位缺失或取值未知則傳送時拒絕。
9. **群發任務 `audience` 欄位擴為 union 型別**(`&#123;type:"tags",...&#125;` / `&#123;type:"contacts",...&#125;`),排程入隊層新增「名單直入」分支跳過標籤反查;OpenAPI 與 Aile UI 解耦,Aile 後臺手工建任務 UI 仍可只暴露標籤篩選不受影響。

### 4.2 推播 webhook 事件(1 項,統一歸入 spec §10.2 `notice.*`)

Aile 側只發**單一事件 `notice.clicked`**;Aile 透過 Postback `data.event` 欄位判別處理流程:`"Broadcast"` = 群發點選,僅發 `notice.clicked`;`"InboundReason"` = 進線原因聯動,Aile 同時啟動 Session 建立流程(詳 §4.6)。業務語義差異由 AiReach 自定欄位(`bizEventCode` / `taskId` / `campaignId` / 業務欄位)承載,Aile 不解析。任務級狀態(建立 / 完成 / 失敗)由 A2 輪詢替代,本期不發獨立事件。

| 事件 | 優先順序 | 觸發時機 | 關鍵 payload 欄位 |
| --- | --- | --- | --- |
| **`notice.clicked`** | **P0** | 使用者點選通知中任一 `Action`(由 Aile 在兩類 `ActionType` 鏈路上統一捕獲,詳 §4.5) | `taskId`(群發任務 ID,來自 A1 返回) / `noticeId`(單條訊息 ID) / `actionIndex` / `action: &#123; type, data &#125;`(透傳 Action) / `contactId` / `serviceNumberId` / `clickedAt` |

> `scope.serviceNumberId` 必填;由 `aile-service-message` 在 Postback / 跳轉包裝 鏈路觸發時呼叫 EventPublishClient。
> 

> **事件統一原則**:AiReach 在 NoticeContent 組裝時**自行將業務事件名編碼進 Postback `data`**(例 `data.bizEventCode = "REDEEM_COUPON_CLICK"`);Aile 僅發一類 `notice.clicked`,AiReach 收到後按 `data` 自定欄位路由內部業務流程。如後續需細分(`notice.delivered` / `notice.bounced` / `notice.complained` / `notice.converted` 等),獨立增列,不在 MVP 範圍。
> 

### 4.3 D 類——客戶 / 標籤 / 受眾(3 項)

> **v1.3.9 修訂**:D 類介面為 **Aile 側客戶標籤**的讀寫入口,保留供**其他 IntegrationApp** 使用;**AiReach 自身不呼叫** D 類——AiReach 營銷標籤由 AiPower 單元自管,詳 §4.7。若 Aile 後續推送任何客戶標籤變更 webhook,BFF 直接丟棄,不寫入 `event_inbox`。
> 

| 代號 | 優先順序 | 方法 + 路徑 | 描述 | 發起方 |
| --- | --- | --- | --- | --- |
| **D1** | **P0** | `POST /openapi/v1/service-numbers/&#123;snId&#125;/contacts/labels:add` | 給一批 contact 在該服務號下打標籤(支援批次 、冪等) | BFF |
| **D2** | **P0** | `POST /openapi/v1/service-numbers/&#123;snId&#125;/contacts/labels:remove` | 移除標籤(批次 、冪等) | BFF |
| D3 | P2 | `GET /openapi/v1/service-numbers/&#123;snId&#125;/contacts/&#123;aileContactId&#125;/labels` | 查詢單個客戶的全部標籤 | BFF |

### 4.4 優先順序總覽(9 項 OpenAPI + 3 項事件 = 12 項)

- **P0(MVP 必備,5 項)**:A1 / A2 / D1 / D2 / `notice.clicked`
- **P1(最佳化體驗,1 項)**:A3
- **P2(擴充套件,6 項;其中 5 項僅在啟用進線原因聯動 §4.6 時所需)**:D3 / **F1** / **F2** / **F3** / **`session.created`** / **`session.closed`**

> 啟用 §4.6 `auto` 模式時,F1 與 `session.created` 升為 P0;`none` 模式下 MVP 僅需 P0 5 項即可上線。
> 

### 4.5 點選捕獲與 webhook 回傳規則(由 Aile 統一負責)

按鈕點選由 Aile 在兩類 `ActionType`(`Postback` / `Url`)鏈路上統一攔截 + 落庫 + 回傳;`notice.clicked` 原樣回傳被點選的 `Action` 欄位(`type` / `data`),應用據此自行歸因。進線觸發沿用 Aile 現行邏輯,可選聯動詳 §4.6。

#### 4.5.1 點選捕獲路徑(兩類 ActionType)

```mermaid
flowchart TB
	Click["使用者點選 Action"]
	subgraph PostbackPath["Postback"]
		P1["客戶端 → Aile postback 端點"]
		P2["Aile 讀取 data.appId<br>(不解析 data 其餘欄位)"]
		P3["按 appId 路由 webhook 接收方"]
	end
	subgraph UrlPath["Url"]
		U1["客戶端 → Aile 跳轉包裝<br>/notice-click/{noticeId}/{actionIndex}"]
		U2["302 至目標 url"]
	end

	Click --> PostbackPath
	Click --> UrlPath
	P1 --> P2 --> P3 --> Common
	U1 --> Common
	U1 --> U2

	Common["aile-service-message 落 notice_click_log<br>(noticeId, actionIndex, type, data, contactId, clickedAt)"]
	Common --> EventPub["EventPublisher 發 notice.clicked webhook<br>(透傳 type / data 兩欄位)"]
```

#### 4.5.2 Aile 側落庫與回傳約束

- 傳送時 Aile 將 `actions[]` 與 `(noticeId, actionIndex)` 持久化關聯,點選事件回撥時一併帶回 `actionIndex`。
- `type=Postback`:Aile **必須**能從 `data` JSON 解出頂層 `appId` 與 `event`,否則傳送時拒絕。
- 點選事件透傳欄位固定為 `action: &#123; type, data &#125;`,其餘 `Action` 欄位(`label` / `url` / `imageUrl` 等)Aile 不在 webhook 中攜帶;如應用需要可按 `(noticeId, actionIndex)` 回查原 notice。
- 進線 / 會話路由由 Aile 側現行邏輯獨立處理,本方案 webhook payload 不含進線相關欄位。

#### 4.5.3 `notice.clicked` webhook payload 示例

```json
{
  "eventType": "notice.clicked",
  "scope": { "serviceNumberId": "sn_xxx" },
  "data": {
    "noticeId": "ntc_xxx",
    "actionIndex": 0,
    "action": {
      "type": "Postback",
      "data": "{\"appId\":\"aireach\",\"event\":\"Broadcast\",\"taskId\":\"bcst_xxx\",\"campaignId\":\"cmp_42\",\"bizEventCode\":\"REDEEM_COUPON_CLICK\",\"couponId\":\"C123\"}"
    },
    "contactId": "ct_xxx",
    "clickedAt": "2026-05-22T10:00:00Z"
  }
}
```

AiReach 收到事件後:

- `type=Postback`(本方案主用) → 解 `data` JSON,按 `event` / `bizEventCode` / `campaignId` 等欄位歸因與路由業務流程(`event=InboundReason` 額外讀 `sourceId`,詳 §4.6)
- `type=Url` → 按 `(noticeId, actionIndex)` 歸因

### 4.6 進線原因聯動(可選)

AiReach 營銷卡片的 Postback 按鈕可選嵌入 Aile 進線原因機制（進線原因規格設計）。粒度 = 每個 Postback Action;同卡片可混用兩種行為。

#### 4.6.1 兩種行為

| 模式 | Postback `data` 頂層形態 | Aile 行為 | AiReach 收到的事件 | 適用場景 |
| --- | --- | --- | --- | --- |
| **不聯動進線**(預設) | `&#123;appId:"aireach", event:"Broadcast", taskId, campaignId, bizEventCode, ...&#125;` | 識別 `event="Broadcast"` → 僅捕獲點選 → 發 `notice.clicked` | `notice.clicked` | 領券 / 跳外鏈 / 調研等不需開啟對話的純 CTA |
| **聯動進線** | `&#123;appId:"aireach", event:"InboundReason", sourceId, taskId, campaignId, bizEventCode, ...&#125;` | 識別 `event="InboundReason"` → 按現行進線原因邏輯建立 Session;同時發 `notice.clicked` | `notice.clicked`  • `session.created`(EntrySource webhook) | 營銷活動承接對話:線上諮詢 / 客服跟進 / lead 經營 |

#### 4.6.2 F 類——進線原因介面(3 項)

| 代號 | 優先順序 | 方法 + 路徑 | 描述 | 發起方 |
| --- | --- | --- | --- | --- |
| **F1** | **P1** | `POST /openapi/v1/entry-sources` | **建立 EntrySource** —— AiReach 在釋出 `auto` 模式 campaign 時呼叫一次。body:`name`(= 活動名) / `reason.type="activity"` / `reason.id=campaignId` / `reason.data=&#123;appId:"aireach",campaignId,...&#125;` / `channels` / `expiresAt`(= 活動結束時間) / `webhook.url`(= BFF 統一 webhook 入口) / `webhook.events=["session.created","session.closed"]`。返回 `sourceId`(供 Postback `data.sourceId` 填入) | Backend 直髮 |
| F2 | P2 | `PUT /openapi/v1/entry-sources/&#123;sourceId&#125;` | 更新 EntrySource(活動改名 / 擴充套件資料調整 / 過期時間延後等) | Backend 直髮 |
| F3 | P2 | `PUT /openapi/v1/entry-sources/&#123;sourceId&#125;/status` | 停用 EntrySource(活動結束時呼叫,改 `status=inactive`) | Backend 直髮 |

> F 類介面不帶 `service-numbers/&#123;snId&#125;` 字首;EntrySource 與服務號透過 `channels` 陣列關聯,而非路徑繫結。
> 

#### 4.6.3 `session.*` webhook 事件(2 項,僅 `auto` 模式訂閱)

| 事件 | 優先順序 | 觸發時機 | 關鍵 payload 欄位 |
| --- | --- | --- | --- |
| **`session.created`** | **P1** | 使用者點選 `event=InboundReason` 的 Postback,Aile 經進線原因流程建立 Session 之後 | `sessionId` / `sourceId` / `contactId` / `serviceNumberId` / `channel` / `entryReason&#123;type,name,id,data&#125;` —— `entryReason.id` 即 AiReach `campaignId`,`entryReason.data` 攜帶 F1 寫入的歸因欄位 |
| `session.closed` | P2 | Session 關閉 | `sessionId` / `sourceId` / `closedAt` / `summary&#123;duration,messageCount,agentId,...&#125;` |

> EntrySource webhook(`session.*`)與 IntegrationApp webhook(`notice.*`)均指向 BFF 統一入口;BFF 按 `eventType` 區分後下發 AiPower。
> 

#### 4.6.4 Postback `data` JSON 頂層欄位表(精確化 §4.0)

| 欄位 | 必填 | 歸屬 | 說明 |
| --- | --- | --- | --- |
| `appId` | **所有 Postback** | Aile 保留 | 固定 `"aireach"`,Aile 據此路由 `notice.clicked` webhook |
| `event` | **所有 Postback 必填** | Aile 保留 | Aile 處理流程判別欄位(對齊 Aile 現行 `event:"InboundReason"` 既定格式)。本方案取值:`"Broadcast"`(群發,Aile 僅發 `notice.clicked`,預設) / `"InboundReason"`(進線原因聯動,Aile 同時啟動 Session 建立流程) |
| `sourceId` | **`event=InboundReason` 時必填** | Aile 保留 | F1 返回的 EntrySource ID |
| `campaignId` | 建議 | AiReach 自定 | AiReach 活動 ID,用於事件歸因 |
| `taskId` | 建議 | AiReach 自定 | A1 群發任務 ID,用於點選事件關聯回任務;webhook payload 也會單獨攜帶 |
| `bizEventCode` | 可選 | AiReach 自定 | AiReach 業務事件名(例 `REDEEM_COUPON_CLICK`),webhook 收到後據此路由內部業務流程 |
| 其餘 | 可選 | AiReach 自定 | 任意業務欄位(如 `couponId`),Aile 不解析、webhook 原樣透傳 |

#### 4.6.5 時序（聯動進線）

```mermaid
sequenceDiagram
    participant AIP as "AiPower 業務流程"
    participant GW as "Aile 閘道器"
    participant ES as "Aile 進線原因服務"
    participant MSG as "aile-service-message"
    participant USR as "使用者"
    participant BFF as "AiReach BFF"

    Note over AIP,ES: 活動釋出:AiPower 同步 EntrySource
    AIP->>GW: F1 POST /openapi/v1/entry-sources<br>(reason.id=campaignId, webhook→BFF)
    GW->>ES: 建立 EntrySource
    ES-->>AIP: 返回 sourceId

    Note over AIP,MSG: 傳送通知,Postback.data 注入 InboundReason + sourceId
    AIP->>GW: A1 POST /broadcasts<br>messages[].actions[].data={appId,event:"InboundReason",sourceId,campaignId,...}

    USR->>MSG: 點選 Postback
    par notice.clicked
        MSG->>BFF: notice.clicked(action.data 原樣透傳)
        BFF->>AIP: 透傳 eventId → event_inbox
    and session.created
        MSG->>ES: event=InboundReason → 建立 Session
        ES->>BFF: session.created(EntrySource webhook)
        BFF->>AIP: 透傳 eventId → event_inbox
    end
    AIP->>AIP: 按 campaignId 關聯兩路歸因

    Note over AIP,GW: 活動結束時停用
    AIP->>GW: F3 PUT /entry-sources/{sourceId}/status (inactive)
```

#### 4.6.6 關鍵約束

- 啟用「聯動進線」的 Postback Action 下,**F1 必須在 A1 建立群發任務之前完成**;sourceId 取得後才能注入 Postback `data`。
- 同一 campaign 內可逐 action 決定是否啟用(粒度 = Postback 按鈕):同卡片可同時含「`event=InboundReason` 的諮詢按鈕」與「`event=Broadcast` 的領券按鈕」。
- `notice.clicked` 與 `session.created` 是兩個獨立事件,可能不同步到達;AiPower 在 `event_inbox` 去重並以 `(campaignId, contactId, actionIndex)` 關聯兩路歸因。
- 未啟用「聯動進線」的 Postback Action 不呼叫 F 類介面,也不訂閱 `session.*` 事件;Aile 不會啟動進線流程,卡片表現為純 CTA。
- EntrySource 與 AiReach campaign 關係約定為 **1:1**(每個 `auto` campaign 建立一條 EntrySource,繫結後複用);如未來需多卡片複用 EntrySource,再擴充套件 N:1。

### 4.7 AiReach 標籤體系與受眾解析(v1.3.9 新增)

#### 4.7.1 標籤邊界口徑

| 標籤體系 | 歸屬 | 使用者 | 與 A1 `audience` 關係 |
| --- | --- | --- | --- |
| **Aile 側客戶標籤** | Aile 服務號客戶進線管理標籤,由 `aile-service-*` 維護 | **其他 IntegrationApp**(保留 D 類介面) | A1 `audience.type="tags"` 模式消費 |
| **AiReach 營銷標籤** | **AiPower 業務單元**(`tag` / `tag_assignment` / `smart_tag_rule`,詳 §5.2) | AiReach 自身 | **不**走 A1 `tags` 模式;在 AiReach 內解析為 `contactIds[]` 後,以 `audience.type="contacts"` 提交 |

**關鍵約束**:

- AiReach **不讀、不寫、不依賴** Aile 側標籤;Aile 也無義務把 AiReach 標籤回寫
- D1 / D2 / D3 介面(§4.3)仍保留給非 AiReach 整合方;AiReach 實現側不再呼叫
- 若 Aile 後續推送任何「客戶標籤變更」webhook,BFF **直接丟棄**,不寫入 AiPower `event_inbox`
- AiReach 標籤按 **`(tenantId, serviceNumberId)`** 作用域隔離;跨服務號同名標籤視為不同標籤
- 標籤來源固定為 `aireach_manual`(運營手動) / `aireach_smart`(智慧規則貼標);不存在 `aile_*` 來源

#### 4.7.2 AiReach 標籤 → A1 audience 解析鏈路

```mermaid
sequenceDiagram
	participant U as "運營"
	participant FE as "React 前端"
	participant BFF as "AiReach BFF"
	participant AIP as "AiPower flow.resolve_audience"
	participant Tag as "tag / tag_assignment 單元"
	participant Aile as "Aile 閘道器"

	U->>FE: 配受眾 = AiReach 標籤 [A AND B]
	FE->>BFF: 提交 aireachTagIds[]
	BFF->>AIP: 觸發 flow.resolve_audience(預覽)
	AIP->>Tag: 查詢命中 aireachContactIds[]
	AIP->>AIP: 過濾已過期臨時標籤 + 排除退訂 / 不可觸達
	AIP-->>BFF: { contactIds[], hitCount, reachableCount }
	BFF-->>FE: 命中預覽
	U->>FE: 確認傳送
	FE->>BFF: 提交活動
	BFF->>AIP: 觸發 flow.dispatch_campaign
	AIP->>AIP: 標籤篩選實時再解析(傳送時快照)→ 寫 broadcast_task.audienceSnapshot
	AIP->>Aile: A1 audience = { type:"contacts", contactIds }
```

**解析時機**:

- **預覽時**(FE 受眾估算):實時解析一次,展示命中數 + 可觸達數
- **傳送時**(任務建立):**再次實時解析**作為最終受眾快照,落入 `broadcast_task.audienceSnapshot`,後續標籤變化不影響已發任務(對齊 MAAC 「傳送時受眾固化」約定)

#### 4.7.3 超過 1000 受眾的拆分策略

A1 `contactIds[]` 上限 1000,AiReach 內部按以下順序處理(Aile 完全不感知):

1. **同 campaign 多子任務**:AiPower 按 1000 一批,建立多個 A1 任務,以 **`parentTaskId`** 關聯;`broadcast_task` 單元新增 `parentTaskId` 欄位
2. **子任務排程**:`schedule.type="immediate"` 全部併發提交;`scheduled` 模式所有子任務共享同一 `at`;`personalized`(Phase 2)各子任務按命中人桶分配
3. **彙總聚合**:`summary` / `status` 在 AiPower 層按 `campaignId` 聚合多個 task 後回展示給 FE
4. **每個子任務對 Aile 而言**就是一次普通 A1 呼叫,無任何新協議

> Phase 2 Smart Sending「按 `bestSendHour` 分桶 → 拆多個 scheduled 子任務」直接複用此基礎設施。
> 

#### 4.7.4 智慧貼標的事件源約束

AiReach 智慧貼標(`smart_tag_rule` 單元,詳 Phase 2 設計頁 §3.8)只可消費 AiPower `event_inbox` 已落庫事件,觸發源對映:

| 觸發型別 | 資料來源事件 | 解析欄位 |
| --- | --- | --- |
| Postback 按鈕點選 | `notice.clicked` | `action.data.bizEventCode`  • `campaignId` |
| Url 按鈕點選 | `notice.clicked` | `(noticeId, actionIndex)`  • Url 模式匹配 |
| 進線開啟會話 | `session.created`(僅 `auto` 模式) | `entryReason.id` = `campaignId` |
| 會話結束 | `session.closed` | `summary.duration` / `summary.messageCount` |
| **N 天未響應** | **AiPower 內部定時 flow** 掃描 `broadcast_task` × `click_attribution` | 不依賴 Aile webhook |

**貼標記錄可追溯欄位**(`tag_assignment` 單元):`sourceRuleId` / `sourceCampaignId` / `sourceTaskId` / `sourceActionIndex` / `sourceBizEventCode`,任一可空。運營在標籤詳情可反查「為什麼這個人被貼上了這個標籤」。

#### 4.7.5 臨時標籤生命週期

- `tag.expiresAt` 欄位標記過期時間(可空 = 永久);臨時標籤典型用法:活動期短期沉澱、AI Segment 命中快照
- 查詢 `tag_assignment` 時實時過濾 `expiresAt > now()`,過期標籤不進入受眾估算與命中
- 每日定時 `flow.expire_temporary_tags` 掃描並歸檔過期標籤(`status` → `archived`),保留歷史 `tag_assignment` 作為審計與歸因依據

---

## 五、AiReach 內部架構

### 5.1 BFF 模組拆分

```mermaid
flowchart TB
	subgraph Edge["接入邊緣"]
		Auth["Auth Adapter<br>(AS SSO + Session)"]
		FEApi["Frontend API"]
		InstallEP["/install /update /uninstall /rotate-secret"]
		WebhookEP["/webhook (Aile)"]
	end

	subgraph Core["核心模組"]
		Proto["Aile Protocol Module<br>(HMAC 籤 / 驗籤 / nonce)"]
		EventDisp["Event Dispatcher<br>(透傳 eventId 給 AiPower)"]
		Aggregator["Aggregator(多單元聚合)"]
		AiffMgr["AIFF Registrar<br>(調 /openapi/v1/aiff/**)"]
		TISync["tenant_integration<br>同步器(→ AiPower)"]
		AiPClient["AiPower OpenAPI Client"]
		AileClient["Aile 閘道器 Client<br>(簽名,僅 install/AIFF 註冊<br>+ 前端聚合所需出站)"]
	end

	subgraph Store["BFF 輕量儲存"]
		DB[("Postgres")]
		Cache[("Redis")]
	end

	FEApi --> Auth
	FEApi --> Aggregator --> AiPClient
	FEApi -.-> AileClient
	InstallEP --> Proto
	Proto --> AiPClient
	Proto --> AiffMgr --> AileClient
	WebhookEP --> Proto --> EventDisp --> AiPClient
	Proto --> AileClient
	Auth --> Cache
	Proto --> DB
```

**關鍵差異 (vs v1.2)**:

- 移除 BFF 側 `event_inbox` 與 Idempotency 模組 → 冪等下沉至 AiPower。
- 新增 **AIFF Registrar** 模組,專門維護該租戶的 AIFF 配置生命週期。
- 嚴格區分 `AS Adapter`(僅 SSO)與 `Aile 閘道器 Client`(install / AIFF 註冊 + **前端聚合所需出站**)。
- **業務後端出站簽名由 AiPower 直髮 Aile 閘道器**,不經 BFF。
- 新增 **`tenant_integration` 同步器**,將 install / rotate-secret 後的 Secret 推送到 AiPower `tenant_integration` 平臺單元。

### 5.2 AiPower 業務單元與流程清單

| 類別 | 名稱 | 關鍵欄位 |
| --- | --- | --- |
| **平臺單元** | **`tenant_integration`** | **aileTenantId / tenantIntegrationId / tenantIntegrationSecret / webhookUrl / status / rotatedAt** |
| **平臺單元** | **`event_inbox`** | **(tenantIntegrationId, eventId) UNIQUE**  • eventType + payloadJson + receivedAt + status |
| 映象單元 | `tenant` | aileTenantId / type / status |
| 映象單元 | `service_number_catalog` | serviceNumberId / name / status |
| 映象單元 | `contact_profile` | (snId, aileContactId) 主鍵 + 屬性 + 關注 + 進線時間 |
| 映象單元 | `user` | aileUserId / role |
| 業務單元 | `campaign` | id / name / serviceNumberId / status / inboundReasonMode(`none`/`auto`) / sourceId(`auto` 模式) |
| 業務單元 | `audience` / `audience_member` | type(`contacts` 名單 / **`aireach_tags`** AiReach 標籤篩選 / `ai_query` Phase 2) / aireachTagIds[] / tagOperator / contactIds[] / memberCount;**所有形態在 dispatch 時統一解析為 A1 `audience.type="contacts"`**  |
| 業務單元 | **`tag`**(AiReach 營銷標籤,v1.3.9 新增) | tagId / tenantId / serviceNumberId / name / source(`aireach_manual` / `aireach_smart`) / kind / color / status / **expiresAt?** / contactCount |
| 業務單元 | **`tag_assignment`**(v1.3.9 新增) | (tagId, aireachContactId) UNIQUE / assignedAt / sourceRuleId? / sourceCampaignId? / sourceTaskId? / sourceActionIndex? / sourceBizEventCode? |
| 業務單元 | **`smart_tag_rule`**(v1.3.9 新增) | ruleId / triggerEvent(`notice.clicked` / `session.created` / `session.closed` / `no_response_for_N_days`) / matchCondition / targetTagId / status / lastExecutedAt / hitCount |
| 業務單元 | `broadcast_task` | taskId(= Aile 側 ID) / campaignId / **parentTaskId?**(超 1000 拆分時關聯) / status / recipientCount / **audienceSnapshot**(傳送時受眾固化) / summary / startedAt / finishedAt |
| 業務單元 | `click_attribution` | (taskId, contactId, actionIndex) / bizEventCode / campaignId / clickedAt |
| 流程 | `flow.contact_entered_to_profile` / `flow.build_audience` / **`flow.resolve_audience`**(標籤→contactIds,v1.3.9) / `flow.dispatch_campaign`(封裝 A1,含超 1000 拆分) / `flow.poll_task_status`(輪詢 A2) / `flow.handle_notice_clicked` / **`flow.apply_smart_tag_rules`**(事件→貼標,v1.3.9) / **`flow.expire_temporary_tags`**(每日,v1.3.9) / `flow.ai_copywriting` | 均依賴 event_inbox 去重 |

### 5.3 資料歸屬

| 資料 | 位置 | 理由 |
| --- | --- | --- |
| contact / visitor / service_number / notice 主資料 | **Aile** | Aile 是唯一權威 |
| campaign / audience / broadcast_task / click_attribution / contact_profile / **AiReach 標籤三件套(`tag` / `tag_assignment` / `smart_tag_rule`)** / **event_inbox** | **AiPower 單元** | AiReach 業務主資料 + AiReach 營銷標籤資產 + 冪等去重表均隨 AiPower 走;**Aile 側客戶標籤**(Aile 獨立維護)與 AiReach 解耦,各自演進 |
| 退訂 / 頻次 / 時間窗 / 轉化判定 | **Aile 群發流水線**（退訂 / 頻次 / 時間窗）+ **AiReach 業務側**（轉化判定） | MVP 不復制治理快照;轉化判定權在 AiReach,結果由 D 類打標籤體現 |
| **`tenant_integration`**(含 Secret) | **BFF 主、AiPower 映象** | BFF 在 install / rotate-secret 時接收並落檔,**同步推送一份映象到 AiPower `tenant_integration` 平臺單元**;AiPower 業務流程出站時本地讀取映象簽名 |
| nonce / token / SSO session | **BFF** | 僅「協議層快取」,不含業務資料 |

### 5.4 傳送主鏈完整時序(三件套協同)

```mermaid
sequenceDiagram
	participant U as "運營人員"
	participant FE as "React 前端"
	participant BFF as "AiReach BFF"
	participant AIP as "AiPower 單元 / 流程"
	participant PI as "Aile 閘道器 + aile-service-*"
	participant WH as "Aile webhook"

	U->>FE: 選服務號 + 建立活動(選 inboundReasonMode)
	FE->>BFF: 儲存 campaign
	BFF->>AIP: upsert campaign
	opt auto 模式
		AIP->>PI: F1 POST /entry-sources(reason.id=campaignId)
		PI-->>AIP: 返回 sourceId,寫回 campaign
	end
	U->>FE: 配受眾(tags 篩選 或 contacts 名單 ≤1000)+ 1..5 則 NoticeContent
	FE->>BFF: 提交群發任務
	BFF->>AIP: 觸發 flow.dispatch_campaign
	Note over AIP,PI: 業務後端出站 = AiPower 直髮 Aile 閘道器(本地讀 tenant_integration 單元簽名)
	AIP->>PI: A1 POST /broadcasts(audience + messages[])
	PI-->>AIP: 返回 taskId
	AIP->>AIP: 寫 broadcast_task,起 flow.poll_task_status
	loop 任務執行中
		AIP->>PI: A2 GET /broadcasts/{taskId}
		PI-->>AIP: status / summary
	end
	WH->>BFF: notice.clicked(action.data 原樣透傳)
	BFF->>AIP: 透傳 eventId → event_inbox
	AIP->>AIP: 首次 → flow.handle_notice_clicked → click_attribution
	opt auto 模式
		WH->>BFF: session.created(EntrySource webhook)
		BFF->>AIP: 透傳 → event_inbox → 關聯 campaignId
	end
	U->>FE: 活動結束
	opt auto 模式
		AIP->>PI: F3 PUT /entry-sources/{sourceId}/status (inactive)
	end
	BFF->>PI: D2 labels:remove(可選,前端聚合 BFF 簽名)
```

---

## 六、前端與 AIFF 整合

### 6.1 AIFF 概念定位

**AIFF** = Aile 側的**前端開發框架**(配置 + 協議),不是打包格式。其工作機制:

1. 應用透過 Aile 閘道器上的 **AIFF 整合 API**(spec v1.0 §9.2 的 `/openapi/v1/aiff/**`)註冊一份 AIFF 配置,宣告:
    - **嵌入位置(slot)**:AileDesktop 的哪個槽位(例:客戶詳情側欄 、服務號工作臺 Tab 、左側主導航 、設定中心子頁等)
    - **endpoint URL**:該槽位應載入的頁面入口地址(通常是該應用自己的 Web 路由)
2. 註冊完成後,AileDesktop 根據配置在對應位置自動載入 endpoint(內嵌 webview / iframe),同時透過 AIFF bridge 注入當前賬號 token / 服務號上下文。
3. AIFF 配置由租戶管理員或 AiReach BFF 在安裝握手後呼叫註冊介面寫入,可後續調 PI 修改。

> AIFF 整合 API 隸屬 Aile 閘道器下的 AIFF 資源域(spec v1.0 §9.2 路由表),由 `aile-service-auth` 承載領域邏輯。
> 

### 6.2 AiReach 的 AIFF 配置策略

AiReach 前端只需**部署一份獨立 React Web**(無需另打 AIFF 包)。AileDesktop 內的嵌入完全由 AIFF 配置驅動:

| AIFF 配置項 | 說明 | AiReach 取值示例 |
| --- | --- | --- |
| 嵌入位置 (slot) | AileDesktop 內的視覺槽位 | 左側主導航增加 "AiReach" 入口;客戶詳情頁右側新增 "近期觸達" 面板;服務號工作臺新增 "營銷活動" Tab |
| endpoint URL | 該槽位載入的頁面入口 | `https://aireach.<corp>.com/embed/main`
`https://aireach.<corp>.com/embed/contact-touch`
`https://aireach.<corp>.com/embed/sn-campaigns` |
| 上下文引數 | 由 AIFF 框架載入時透傳的 URL 引數 / bridge 注入 | `tenantId` / `serviceNumberId` / `contactId` / Aile token |
| 可見性 / 許可權 | 哪些角色可見 / 可操作 | 租戶管理員 、營銷運營 |

### 6.3 AIFF 配置寫入流程

```mermaid
sequenceDiagram
	participant BFF as "AiReach BFF"
	participant PI as "Aile 閘道器"
	participant AIFF as "aile-service-auth<br>(AIFF 資源域)"
	participant Desktop as "AileDesktop"
	participant FE as "AiReach React Web"

	Note over BFF,AIFF: 通常在 /install 之後自動寫入
	BFF->>PI: 簽名 POST /openapi/v1/aiff/configurations
	PI->>AIFF: 註冊 slot + endpoint URL + params
	AIFF-->>BFF: 註冊成功
	Note over Desktop,FE: 使用者使用階段
	Desktop->>AIFF: 獲取當前租戶的 AIFF 配置
	Desktop->>FE: 載入 endpoint URL + 注入 token / 服務號上下文
	FE->>BFF: 攜帶注入 token 建會話
	BFF-->>FE: 返回會話
```

### 6.4 AiReach 計劃註冊的 AIFF 槽位(初版)

| 槽位 | endpoint | 作用 | Phase |
| --- | --- | --- | --- |
| 左側主導航 "AiReach" | `/embed/main` | 營銷控制檯主入口,展示活動列表 + 服務號選擇 | Phase C |
| 服務號工作臺 "營銷活動" Tab | `/embed/sn-campaigns` | 當前服務號下的活動列表與新建入口 | Phase C |
| 客戶詳情 "近期觸達" 面板 | `/embed/contact-touch` | 顯示該客戶在該服務號下的最近 N 條 notice 與轉化結果 | Phase D |
| 設定中心 "AiReach 設定" | `/embed/settings` | 退訂、頻次 、營銷時間窗的租戶設定 | Phase D |

### 6.5 前端兩種開啟方式的差異點

一份程式碼,兩種開啟:獨立 Web(`/app/*` 路由) 與 AIFF 槽位(`/embed/*` 路由)。差異僅在登入 、上下文來源與外殼:

- **登入**:獨立 Web 重定向 BFF 走 AS SSO;AIFF 槽位讀取 AIFF 框架注入的 token,BFF 校驗後建會話。
- **上下文**:獨立 Web 由 URL / 使用者選擇;AIFF 槽位從 bridge 注入(`tenantId` / `serviceNumberId` / `contactId`)。
- **外殼**:獨立 Web 帶頂欄 / 側欄;AIFF 槽位複用 AileDesktop 外殼,隱藏頂側欄。
- **適配層**:手機抽象 `ShellAdapter` + `AuthAdapter`,程式碼上僅一處 if/else 。

---

## 七、完整場景走查(MVP 一次活動為線索)

本節按 MVP 推播鏈路展開一次完整營銷活動的關鍵步驟;`auto` 模式增補步驟標註「opt auto」。

| # | 步驟 | 主要參與方 | 關鍵動作 |
| --- | --- | --- | --- |
| 1 | 租戶啟用 + AIFF 註冊 | Aile 管理員 → PI → BFF → AiPower | install 握手落 `tenant_integration`;BFF 同步至 Backend;BFF 調 `/openapi/v1/aiff/configurations` 註冊槽位 |
| 2 | 建立 campaign | 運營 → FE → BFF → AiPower | 選服務號、活動名等基礎欄位，寫入 campaign 單元 |
| 3 | 可選：為某個 Postback Action 開啟「進線聯動」並登記 EntrySource | AiPower → Aile 閘道器 | 當訊息內容的某個 Action 選擇「Postback + 聯動進線」時：AiPower 調 **F1** `POST /openapi/v1/entry-sources` 建立 EntrySource（`reason.id=campaignId` 等），取得 `sourceId` 供該 Action 的 Postback `data` 注入 |
| 4 | 配受眾 + 組裝 NoticeContent | 運營 → FE → BFF → AiPower | 選 `tags` 篩選 或 `contacts` 名單(≤ 1000);組裝 1..5 則 NoticeContent：支援 `Postback` / `Url`。當選擇 `Postback` 時，可按 Action 維度勾選是否「聯動進線」：勾選則注入 `event:"InboundReason"`  • `sourceId`；不勾選則注入 `event:"Broadcast"` |
| 5 | 發起群發任務 | AiPower → Aile 閘道器 | **A1** `POST /openapi/v1/service-numbers/&#123;snId&#125;/broadcasts`,返回 `taskId`;寫 `broadcast_task` 單元 |
| 6 | 任務狀態輪詢 | AiPower → Aile 閘道器 | `flow.poll_task_status` 間隔輪詢 **A2** `GET /broadcasts/&#123;taskId&#125;`,重新整理 `broadcast_task.status` / `summary` |
| 7 | 使用者點選回傳 | 使用者 → Aile webhook → BFF → AiPower | `notice.clicked` 透傳至 BFF,驗籤後透傳 `eventId`;AiPower `event_inbox` 去重 → `flow.handle_notice_clicked` 寫 `click_attribution` |
| 8 | opt auto:Session 建立 | Aile EntrySource → webhook → BFF → AiPower | 使用者點選 `event=InboundReason` Postback → Aile 建立 Session,發 `session.created`;AiPower 按 `campaignId` 關聯兩路歸因 |
| 9 | 活動結束 | 運營 → FE → BFF → AiPower | 關閉 campaign;**opt auto**:AiPower 調 **F3** `PUT /entry-sources/&#123;sourceId&#125;/status` 改 `inactive` |
| 10 | 可選:摘標籤收尾 | BFF → Aile 閘道器 | 前端聚合觸發 **D2** `labels:remove` 清理活動期臨時標籤 |

---

## 八、開發路線圖

| 階段 | 目標 | 關鍵交付 | 依賴 |
| --- | --- | --- | --- |
| **Phase A — 協議骨架** | BFF 接 install + webhook + AiPower event_inbox + 一條單元流程跑通 | BFF: install / webhook 驗籤 、AS SSO Adapter 、Aile 閘道器 Client 、AiPower Client;AiPower:**event_inbox 單元**(冪等去重) + tenant / service_number_catalog / contact_profile 映象單元 + `flow.contact_entered_to_profile` | spec v1.0 + AiPower OpenAPI + AS |
| **Phase B — 業務單元與獨立 Web** | 手工活動可跑;`/app/*` Web 可訪問 | AiPower:campaign / audience / broadcast_task 單元 + `flow.build_audience`;BFF 聚合介面;React 頂級頁面 + ShellAdapter 骨架 | Aile contact.* 事件 |
| **Phase C — MVP 群發推播 + AIFF 入口** | 群發跑通;**AIFF 入口可嵌**(主導航 + 服務號工作臺) | flow.dispatch_campaign + flow.poll_task_status + flow.handle_notice_clicked;**A1 / A2 / D1 / D2 / notice.clicked**;**BFF AIFF Registrar + `/embed/main` / `/embed/sn-campaigns` 路由** | **Aile P0 介面**  • **AIFF 整合 API** |
| **Phase D — 進線聯動 + 詳情頁 AIFF** | auto 模式起線 + AI 文案 + **客戶詳情 / 設定 AIFF** | **A3 / D3 / F1 / session.created**;AiPower AI SDK + 排程;`/embed/contact-touch` `/embed/settings` | **Aile P1 介面**  • AiPower AI / 排程 |
| **Phase E — 效果與智慧化** | EntrySource 生命週期 + 智慧受眾 | **F2 / F3 / session.closed**;智慧受眾 + AI 總結 | **Aile P2 介面**  • AiPower AI |

---

## 九、關鍵設計決策彙總

| 決策項 | 口徑 | 理由 |
| --- | --- | --- |
| AiReach 實現形態 | 三件套:AiReach Backend Service(獨立服務,業務) + Node BFF(協議 + 聚合 + AIFF 註冊) + 一份 React Web | 複用 AiPower 快速建制;BFF 擔當協議 與聚合 |
| Aile 整合入站協議 | **BFF**:install / update / uninstall / webhook / AIFF 註冊;**不**承擔業務後端出站簽名 | Node 適合高併發 webhook、動態簽名、多租戶會話 |
| **業務後端出站簽名** | **AiReach Backend Service 直髮 Aile 閘道器**;`tenant_integration` Secret 由 BFF install 時同步至 Backend | BFF 本質是 AiReach 前端聚合層,後端不應主動呼叫 BFF |
| **SSO** | **走 AS**(Aile 生態統一認證服務、獨立服務)完成 OAuth / Token 校驗 | **AS 不同於 `aile-service-*` 套件**,是獨立服務 |
| **事件冪等去重** | **AiPower `event_inbox` 單元**(`UNIQUE(tenantIntegrationId, eventId)`);BFF 僅驗籤 + 透傳 | 業務主資料與冪等表必須同租戶上下文,避免跨服務事務 |
| 業務主資料 | 全部落在 AiReach Backend(含 event_inbox);BFF 僅存協議層狀態 | BFF 輕體;升級、遷移都走 AiPower |
| **AIFF 嵌入** | **一份 React Web**  • 多個 AIFF 配置註冊(槽位 + endpoint URL);不打包 AIFF 包 | AIFF 是 Aile 前端開發框架,以配置驅動嵌入 |
| Backend 呼叫入口 | 僅經 BFF Backend Client(API),不直連 DB | 平臺升級兌現能力 |
| activity 作用域 | 服務號級,campaign.serviceNumberId 必填且不可變 | 對齊 spec v1.0 |
| 退訂 / 頻次 / 時間窗 | 沿用 Aile 群發流水線治理;AiPower 不復制治理快照,轉化判定由 D 類打標籤體現 | MVP 不復制治理狀態,避免業務層與底座不一致 |
| **通知訊息組合** | **AiReach 按 NoticeContent 契約自行組合**(無模板),Aile 僅做結構 + 安全檢測 | 避免模板膨脹;AI 文案 / 個性化更靈活 |
| **群發受眾形態** | **A1 `audience` 欄位 union 型別**:`&#123;type:"tags", tagIds[], tagOperator&#125;` 標籤篩選(複用 Aile UI 群發邏輯)或 `&#123;type:"contacts", contactIds[]&#125;` 名單直傳(單任務 ≤ **1000**) | AiReach 業務側已算出精準名單時無需繞道臨時打標;OpenAPI 與 Aile UI 解耦,運營手工建任務不受影響 |
| **AiReach 標籤歸屬(v1.3.9)** | **AiReach 營銷標籤由 `tag` / `tag_assignment` / `smart_tag_rule` 三件套在 AiPower 自管**;Aile 側 D 類標籤介面保留給其他 IntegrationApp,AiReach 不呼叫;AiReach 受眾一律以 A1 `audience.type="contacts"` 提交;Aile 推送的任何客戶標籤變更 webhook,BFF 直接丟棄 | 標籤是 AiReach 長期沉澱的核心營銷資產,需獨立演進(臨時標籤 / 智慧貼標 / 標籤洞察 / 來源可追溯),不應與 Aile 進線管理標籤耦合 |
| **超 1000 受眾拆分(v1.3.9)** | AiReach 內部按 1000 拆多個 A1 子任務,以 `parentTaskId` 關聯,Aile 不感知拆分;Phase 2 Smart Sending 複用此機制 | A1 `contactIds[]` 上限是 Aile 群發現行約束;拆分邏輯收斂在 AiReach 內,Aile 零侵入 |
| **AI 編排域歸屬(v1.4)** | **Copilot 對話編排 / 多 Agent / skills / RAG / MCP 由 AileAI 承接**;AiReach Backend 作為資料與統計/工具域,把資料能力工具化為 Tool API 供 AileAI 呼叫;BFF 增加 SSE 中繼 + 薄 AI 閘道器;Aile / AS 底座零侵入。Phase 2 引入,MVP 不啟用 | 對話編排與知識檢索屬 AI 專屬能力,與業務資料域解耦更利於演進與 LLM 計費 / 降級獨立管控;詳見 Phase 2 方案 |
| **Action 欄位口徑** | **對齊 Aile 真實 Java `Action` 模型**(本方案使用欄位子集):`type` / `label` / `data` / `url` / `title` / `text` / `imageUrl` / `displayText` / `isDefault`;本方案使用 `ActionType` = `Postback` / `Url` 兩類(`Aiff` / `Action` 屬 AIFF 嵌入觸發 / 匿名歸戶等內部場景,本方案不涉及);`data` 由 AiReach 自定 JSON,Aile 不解析(`Postback` 頂層 `appId` / `event` 除外) | 避免抽象欄位與 Aile 真實模型不一致 |
| **點選捕獲 + webhook 回傳** | **由 Aile 統一負責**:兩類 `ActionType`(`Postback` / `Url`)鏈路點選統一捕獲 + 落庫 + 回傳;`notice.clicked` 原樣透傳 `action: &#123; type, data &#125;` 兩欄位;**進線觸發沿用 Aile 現行邏輯**,可選聯動詳 §4.6 | 契約面收斂到 Aile 真實 `Action` 模型;應用歸因自治 |
| 需 Aile 側新增介面 | **9 項 OpenAPI + 3 項 webhook 事件 = 12 項**(§四;`notice.clicked` × 1 + `session.*` × 2,後者僅 `auto` 模式訂閱) | 不補 P0 不能上線 |
| **進線原因聯動(可選)** | **campaign / action 級 `inboundReasonMode` 配置**:所有 Postback 頂層注入 Aile 保留 schema `&#123;appId, event&#125;`;`none` = `event:"Broadcast"`(純 CTA,Aile 僅發 `notice.clicked`);`auto` = AiReach 調 **F1** 在 Aile 建立 EntrySource,注入 `event:"InboundReason"`  • `sourceId`,Aile 同時發 `notice.clicked` 與 `session.created` 給 BFF;粒度可逐 action 決定 | 營銷場景分流:領券 / 跳鏈不開對話;諮詢 / 客服跟進自動起線;不強制全量繫結 |

---

## 十、修改歷程

| 版本 | 日期 | 作者 | 修訂摘要 |
| --- | --- | --- | --- |
| v0.1 | 2026-05-20 | chunlei zhu | 初版:「AiPower 之上的 CRM 應用」假設下的粗粒度功能描述 |
| v1.0 | 2026-05-21 | chunlei zhu | 對齊 spec v1.0 深度重寫:AiReach 與 AiPower 同級獨立 IntegrationApp(後在 v1.1 調整);補齊註冊 / 安裝 / 事件 / OpenAPI 四段鏈路;引入服務號級強約束;三模式推播矩陣 |
| v1.1 | 2026-05-21 | chunlei zhu | 重新定位為三層架構(Aile / AiPower / AiReach);僅 AiReach 接入 Aile;大幅擴充 Aile 側需補齊的 5 類 15 項介面與 P0/P1/P2 優先順序;內部增 ComplianceAppService 與各治理快照表;完整傳送主鏈補上退訂雙檢 、配額 / 時間窗預檢 、轉化回寫 |
| v1.2 | 2026-05-21 | chunlei zhu | 明確 AiReach 實現形態 = 三件套:1) AiPower 重定義為 Java 開發平臺(快速建制單元 + 流程),AiReach 業務後端 = 在 AiPower 內建制的單元 + 流程,**不再獨立寫 Java 微服務**;2) 新增 Node BFF 作為前端聚合層 + Aile 整合協議層 + Aile SSO + AiPower 整合;3) 前端 React 一份程式碼兩種釋出形態(獨立 Web + AIFF) |
| **v1.3** | **2026-05-21** | **chunlei zhu** | **四點澄清重寫**:1) **AS 修正**為 Aile 生態統一認證服務(獨立服務),全文不再將 AS 等同於 `aile-service-*` 套件;2) **AIFF 重新定位**為 Aile 側前端開發框架,透過 `/openapi/v1/aiff/**`(spec v1.0 §9.2)註冊「槽位 + endpoint URL」,前端只部署一份 React Web 即可被多個 AIFF 槽位複用,**不再打包 AIFF 包**;3) **事件冪等去重**從 BFF 下沉到 **AiPower `event_inbox` 單元**(`UNIQUE(tenantIntegrationId, eventId)`),BFF 僅驗籤 + 透傳 eventId;4) BFF 新增 AIFF Registrar 模組,在安裝握手後批次註冊 AIFF 槽位;§六 全章重寫;資料歸屬表 、決策表 、路線圖同步對齊 |
| **v1.3.1** | **2026-05-22** | **chunlei zhu** | **出站職責重切 + 術語統一**:1) **業務後端出站呼叫** AiPower 單元 / 流程**直接**簽名呼叫 **Aile 閘道器**(原:經 BFF 代發),因 BFF 本質是 AiReach 前端聚合層,後端不應主動呼叫 BFF;2) 新增 **`tenant_integration` 作為 AiPower 平臺單元**,BFF 在 install / rotate-secret 時把 `tenantIntegrationSecret` 同步落檔,供業務流程出站時本地讀取簽名;3) BFF 僅保留 install / webhook / AIFF 註冊等入站協議動作 + 前端聚合所需的 Aile 出站呼叫;4) 全文術語統一:「PI 閘道器」→「**Aile 閘道器**」;5) §3.4 時序圖 / §5.4 傳送主鏈 / §5.2 單元清單 / §5.3 資料歸屬 / §4 呼叫方表 / §1.1 BFF 職責 / §9 決策表 同步重寫 |
| **v1.3.2** | **2026-05-22** | **chunlei zhu** | **通知模板態取消 + 點選 / 進線 / webhook 由 Aile 編排**:1) Aile 不再維護通知模板,AiReach 按 **NoticeContent 契約**(title / image / describe + buttons[],四類 actionType)自行組合訊息體,Aile 僅做結構校驗 + 內容安全檢測;原 A1 / A2 介面取消;2) 新增 **A0 `POST /notices`** 接收 inline NoticeContent;A3 預覽語義改為「接 NoticeContent 返回渲染結果」;3) **點選主動回寫(原 C1)取消** —— 所有按鈕點選由 Aile 在 postback / 跳轉包裝 / AIFF / action 鏈路上自動捕獲併發 `notice.clicked`;4) **進線規則與觸發由 Aile 側維護**(按 serviceNumberId / actionType / payload.clickId),AiReach 不感知;5) **`notice.clicked` event payload 攜帶 `inbound` 子結構**(triggered / conversationId / reason),整合方收一條事件即知點選 + 進線;6) **postback button payload 契約固化**:`appId`(Aile 路由 webhook) + `clickId`(語義) + `extra`(業務欄位);7) §四 介面口徑調整為 **16 項 OpenAPI + 5 項 `notice.*` 事件 = 21 項**;8) §九 決策表追加「通知訊息組合」「點選 / 進線 / webhook 聯動」兩條決策行 |
| **v1.3.3** | **2026-05-22** | **chunlei zhu** | **對齊 Aile 真實 `Action` 欄位定義 + 簡化點選事件 payload**:1) §4.0 NoticeContent 契約**完全改用** Aile Java `Action` 模型(`type` / `label` / `code` / `data` / `url` / `title` / `text` / `imageUrl` / `displayText` / `isDefault`),`ActionType` 列舉固化 `Postback` / `Url` / `Aiff` / `Action`(對齊匿名訪客實名歸戶、聊天室切換與模板 Action 設計方案;匿名歸戶系統卡片字典首批必備 `OPEN_ROOM` / `OPEN_MERGE_DETAIL`);2) **點選歸因載體重定義**:`Action` 型別用 `code` 歸因,`Postback` 型別用 `data` 內自定 JSON 欄位歸因(AiReach 自定 schema,Aile 不解析);取消抽象 `buttonId` / `actionType+payload` 命名;3) **Postback `data` 強約定**:必須為合法 JSON 字串且頂層含 `appId` 欄位(Aile 據此路由 webhook 接收方);4) **`notice.clicked` payload 簡化**:僅透傳 `action: &#123; type, code, data &#125;` 三欄位 + `actionIndex`  • 通用上下文,移除 `inbound` 子結構;5) **進線觸發規則下線**:沿用 Aile 現行進線邏輯,本方案不再設計;§4.8 原「點選 / 進線聯動規則」改寫為「點選捕獲與 webhook 回傳規則」;6) §4.9 / §九 決策表追加「Action 欄位對齊」「點選歸因載體」「Postback data 強約定」「`notice.clicked` payload」四條調整項 |
| **v1.3.4** | **2026-05-22** | **chunlei zhu** | **§四 收斂 `ActionType` 使用範圍**:AiReach 營銷場景僅使用 `Postback` / `Url` / `Aiff` 三類,`Action` 本地行為型別屬匿名歸戶等內部場景,與本方案無關;1) §4.0 移除 `code` 欄位定義、`type=Action` 語義行、首批 `Action.code` 定義表、`type=Action` 示例卡片與 `actionHandlers` 前端分發 JS;2) `Action.data` 歸屬重寫為僅 `Postback` / `Aiff` 適用,點選歸因表述統一為「`Postback` 主用」;3) §4.8 點選捕獲路徑 mermaid 與 `notice.clicked` 歸因說明同步去除 `Action` 鏈路;4) §九 決策表「Action 欄位口徑」「點選捕獲 + webhook 回傳」兩行同步收斂為三類口徑 |
| **v1.3.5** | **2026-05-22** | **chunlei zhu** | **§四 MVP 收斂 + 複用 Aile 現行服務號群發**:1) §4.1 A 類重寫為「群發任務介面」(A1 建立 / A2 查詢 / A3 取消,3 項),對齊 Aile 後臺「新建群發任務」UI(任務名 / 備註 / 渠道 / 1..5 則訊息 / 客戶標籤篩選 / 立即或定時);原 A0 inline 傳送、A3 渲染預覽、A4 單條狀態、A5 單條統計、A6 推播額度全部取消;Aile 側需配套支援:群發任務 OpenAPI 入口 + `messages[]` 卡片混合 + 客戶標籤列表 + `notice.clicked` payload 攜帶 `taskId`;2) §4.2 B 類(合規預檢)取消,沿用 Aile 群發現行 退訂 / 頻次 / 時間窗 治理;3) §4.3 C 類(轉化主動回寫)取消,轉化結果由 §4.5 D 類 打標籤替代;4) §4.4 推播 webhook 收斂為**單一事件 `notice.clicked`**(原 5 項 → 1 項),`notice.task_completed` / `bounced` / `complained` / `converted` 取消,任務級狀態由 A2 輪詢;業務事件名由 AiReach 編碼進 Postback `data.bizEventCode`,Aile 不解析;5) §4.6 E 類(AI / 高階受眾)取消;6) §4.7 總覽更新為 **9 項 OpenAPI + 3 項事件 = 12 項**(P0 5 項 / P1 2 項 / P2 5 項,P2 全部為進線原因聯動相關);callout、§四 intro、§九 決策表介面數同步更新;§5.4 傳送主鏈 mermaid / §八 路線圖 / §九 介面資料歸屬表中對舊 A1-A6 / B / C / E 代號的引用,待下版統一收斂 |
| **v1.3.6** | **2026-05-22** | **chunlei zhu** | **Postback `data` 頂層引入 `event` 判別欄位(對齊 Aile 現行 `event:"InboundReason"` 格式)**:1) `event` 升為所有 Postback 頂層必填的 Aile 保留欄位,本方案取值 `"Broadcast"`(群發,Aile 僅發 `notice.clicked`)或 `"InboundReason"`(進線原因聯動,Aile 同時啟動 Session);§4.1 Aile 側配套支援追加「識別 `event="Broadcast"`」一項;2) §4.0 例與 §4.8.3 webhook payload 示例增補 `event:"Broadcast"`  • `taskId`  • `bizEventCode`,`bizCode` 統一更名為 `bizEventCode`;3) §4.0 健壯性 / 契約小結 / 歸因載體 同步說明 `event`  • `appId` 缺失則 Aile 傳送時拒絕;4) §4.4 webhook intro 說明 Aile 按 `data.event` 判別處理流程;5) §4.9.1 `none` 模式 `data` 形態更新為含 `event:"Broadcast"`;§4.9.4 欄位表 `event` 行改為「所有 Postback 必填」、新增 `taskId` 行、`bizCode` 改名為 `bizEventCode`;6) §九 決策表「進線原因聯動」行同步收斂 |
| **v1.3.7** | **2026-05-22** | **chunlei zhu** | **A1 群發任務 `audience` 欄位擴為 union 型別(支援名單直傳)**:1) `audience` 由 `&#123;tagIds[], tagOperator&#125;` 改為 union 二選一形態:`&#123;type:"tags", tagIds[], tagOperator&#125;` 標籤篩選 或 `&#123;type:"contacts", contactIds[]&#125;` 名單直傳,**單任務 `contactIds[]` 上限 1000**;2) §4.1 A1 介面體重寫,`audience` 欄位更新為 union 形態;3) §4.1 Aile 側配套支援第 4 項改為按 `audience.type` 分支校驗,新增第 9 項:Aile 群發任務模型 `audience` 擴為 union + 排程入隊層增加「名單直入」分支(跳過標籤反查),OpenAPI 與 Aile UI 解耦,運營手工建任務 UI 不受影響;4) §四 章節 intro 增補名單直傳說明;5) §九 決策表新增「群發受眾形態」一行 |
| **v1.3.8** | **2026-05-23** | **chunlei zhu** | **通篇 MVP 收斂 + §四 節號順延 + Aiff 收斂兩類**:1) Callout 與 §三 收斂 MVP 推播鏈路口徑;2) §4.0 NoticeContent / Action 收斂為 `Postback` / `Url` 兩類(`Aiff` / `Action` 屬 AIFF 嵌入觸發 / 匿名歸戶等內部場景,本方案不涉及),`data` 頂層保留欄位統一為 `appId`  • `event`;3) §四 刪除佔位與 D4,節號順延為 4.0 / 4.1 / 4.2 / 4.3 / 4.4 / 4.5 / 4.6;4) §4.5 點選捕獲 mermaid 刪 `Aiff` 子圖、payload 改 `action: &#123; type, data &#125;` 兩欄位;5) §5.2 刪模板快取 / 治理單元,補 `inboundReasonMode` / `sourceId` / `broadcast_task` / `click_attribution` / `flow.dispatch_campaign` / `flow.poll_task_status` / `flow.handle_notice_clicked`;§5.3 「退訂 / 頻次 / 時間窗」改為「沿用 Aile 群發流水線」;6) §5.4 傳送主鏈 mermaid 重寫為 MVP 實際鏈路(A1 建立 → A2 輪詢 → `notice.clicked` → opt `session.created` → opt F3 停用);7) §七 重寫為 MVP 一次活動場景表;8) §八 路線圖 Phase C / D / E 關鍵交付改為新代號(A1 / A2 / D1 / D2 / `notice.clicked` → A3 / D3 / F1 / `session.created` → F2 / F3 / `session.closed`);9) §九 決策表「退訂 / 頻次 / 時間窗」「Action 欄位口徑」「點選捕獲 + webhook 回傳」三行同步收斂為 MVP 口徑 |
| **v1.3.9** | **2026-05-26** | **chunlei zhu** | **AiReach 標籤體系自治 + 受眾解析鏈路澄清**:1) Callout 新增「AiReach 標籤體系自治」要點;2) §4.1 A1 `audience` 欄位說明更新:`tags` 模式 = **Aile 側標籤**,保留供其他 IntegrationApp 使用,AiReach 不消費;AiReach 永遠走 `contacts` 模式;3) §4.3 D 類追加 intro 註明 AiReach 不呼叫,僅供其他 IntegrationApp;BFF 丟棄 Aile 推送的客戶標籤變更 webhook;4) **新增 §4.7「AiReach 標籤體系與受眾解析」**,含 §4.7.1 邊界口徑 / §4.7.2 標籤→A1 解析時序(預覽 + 傳送兩次解析,傳送時落 audienceSnapshot) / §4.7.3 超 1000 拆分策略(`parentTaskId`) / §4.7.4 智慧貼標事件源對映(Postback / Url / session / N 天未響應) / §4.7.5 臨時標籤生命週期;5) §5.2 新增 AiPower 業務單元三件套 `tag` / `tag_assignment` / `smart_tag_rule`;補 `flow.resolve_audience` / `flow.apply_smart_tag_rules` / `flow.expire_temporary_tags`;`broadcast_task` 增 `parentTaskId` / `audienceSnapshot`;`audience` 單元 type 改為 `contacts` / `aireach_tags` / `ai_query` 並明確「dispatch 時統一解析為 A1 contacts」;6) §5.3 資料歸屬表標籤三件套歸 AiPower,與 Aile 客戶標籤解耦;7) §九 決策表新增「AiReach 標籤歸屬」與「超 1000 受眾拆分」兩行 |
| **v1.4** | **2026-05-29** | **chunlei zhu** | **納入 AileAI 整合（Phase 2 對齊）**：1）Callout 新增「AI 編排域 = AileAI」要點；2）§一 命名錶新增「AI 編排層 AileAI」行；3）§二 新增 §2.4 四方全景架構圖（Aile × AS × AiPower × AileAI × AiReach），明確 **AiPower = 資料與統計 / 工具域**、**AileAI = AI 編排域** 的職責解耦，BFF 增 SSE 中繼 + 薄 AI 閘道器；4）§九 決策表新增「AI 編排域歸屬」行。AileAI 為 Phase 2 引入，MVP 不啟用 |
| **v1.4.1** | **2026-06-01** | **chunlei zhu** | **進線聯動口徑調整**：取消「none/auto」模式分類與 campaign 基本資訊中的進線聯動配置；改為在 **訊息內容的 Postback Action 維度**決定是否聯動進線——聯動則先建立 EntrySource 並注入 `event:"InboundReason" + sourceId`，不聯動則注入 `event:"Broadcast"` |
| **v1.5** | **2026-06-11** | **chunlei zhu** | **架構方向反轉——AiReach 自建獨立 Backend,不再基於 AiPower**:1)新增 **§〇 架構方向變更**(決策宣告 + 調整後整體架構圖 + 職責搬遷對照表 + 全域性口徑替換規則);2)業務後端由「AiPower 單元 + 流程」改為 **AiReach Backend Service(獨立服務,Java / Node 自選)**,自有 DB + 排程 + 多租戶隔離 + `event_inbox` 冪等 + `tenant_integration` 金鑰 + Tool API 均下沉至 Backend;3)業務出站簽名改由 **Backend 直髮 Aile 閘道器**;4)資料與統計 / 工具域改由 **AiReach Backend** 承載;5)Callout、§一命名錶、§1.1 三件套、§九決策表同步更新;§二~§八 詳細時序 / 資料模型沿用舊標籤,按 §〇.3 規則換算,後續版本逐節落地 |
