docs: add IM platform binding

This commit is contained in:
JzoNg
2026-07-16 21:26:06 +08:00
parent dce8e971be
commit abcc77204b
6 changed files with 676 additions and 0 deletions
@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-07-14
@@ -0,0 +1,193 @@
## Context
本 change 只覆盖 Contacts 领域中的 Organization 级 IM platform 绑定与通讯录同步详情。它不涉及 Agent 发布、Agent Roster、App access point 或 workflow node binding。Figma 文件虽然名为 “Agent Roster”,但用户已经明确这些节点表达的是 Contacts 的 IM platform 管理 UI。
已有 `hitl-im-contact-domain-discovery` change 已确认以下领域约束,本 change 直接复用而不重新定义:
- 同一 Organization 一期只启用一个 IM platform。
- EE 由企业管理员管理,CE / SaaS 由 workspace owner 或 workspace admin 管理。
- 连接状态包含 `Not configured``Configured``Connected``Permission issue``Callback error``Connection error`
- 通讯录同步由管理员手动触发,不做自动同步。
- 同步优先按 platform user ID 匹配已有 binding,再按 Email 匹配 Contact;未命中对象进入 unmatched,不能自动创建 External contact。
本 change 的实现范围严格限定为前端。后端 contract 尚未就绪,因此页面、查询、mutation、权限、provider availability、同步任务和同步详情均由集中、类型安全、确定性的 mock repository 驱动。后续真实 API 接入必须通过独立 change 完成。
当前 web 中的 `web/features/agent-v2/roster/` 是 AI Agent 资产管理,不能作为 Contacts UI 的实现位置。Contacts feature 需要拥有自己的组件、数据访问抽象和路由边界,并由 EE 与 CE / SaaS 的不同管理 shell 挂载。
设计验收来源:
| 范围 | Figma node |
| -------- | -------------------------------------------------- |
| 绑定界面 | `1649:6572``1613:5906``1646:5214``1646:5959` |
| 同步详情 | `1634:5098``1634:5104` |
## Goals / Non-Goals
**Goals:**
- 在 Contacts 管理区域提供从未绑定、配置、mock 授权、连接异常到已连接的完整 IM platform 管理体验。
- 通过同一套 Contacts feature UI 适配 EE 企业管理面和 CE / SaaS workspace 管理面。
- 支持手动启动 mock 通讯录同步、恢复 mock 进行中任务、查看最新摘要和指定 sync run 详情。
- 清晰表达 matched、created binding、updated binding、unmatched、skipped、failed 等结果,帮助管理员理解联系人映射。
- 将数据访问集中在可替换的 typed repository,避免页面组件直接依赖 fixture shape。
- 遵循 i18n、dify-ui、可访问性和前端测试约束。
**Non-Goals:**
- 不实现或修改 Agent、Agent Roster、Agent access point 或 workflow Agent binding。
- 不在本 change 中实现 Contact CRUD、External contact 创建、workspace IM override 或单个 Contact 的 IM identity 编辑。
- 不实现 unmatched 的手动映射、忽略或转 Contact 操作;同步详情保持只读。
- 不修改后端 API、OpenAPI schema、生成式 client、领域模型、数据库迁移、Celery task、provider adapter 或 credential 加密逻辑。
- 不执行真实 OAuth、真实 provider callback、真实网络连接测试、真实目录同步或服务端权限校验。
- 不支持同一 Organization 同时启用多个 IM platform。
- 不建设完整同步历史审计产品;只展示当前进行中的任务、最近结果和由 `sync_run_id` 指定的 mock 详情。
## Decisions
### 1. Contacts feature 独立拥有 UI,并由不同管理 shell 挂载
实现建立 Contacts-owned feature 模块,包含 binding summary、provider setup、connection diagnostics、sync trigger 和 sync details。EE 企业管理面与 CE / SaaS workspace 管理面只负责提供 Organization context、mock permission context 和返回路径。
AI Agent Roster 与 Human Contacts 的数据、权限和生命周期完全不同,因此不复用 `web/features/agent-v2/roster/`
### 2. Typed mock repository 是唯一数据边界
组件不得直接 import 零散 JSON fixture,也不得在组件内按场景硬编码响应。feature 定义稳定的前端 view model 和 repository interface,例如:
```text
ContactIMIntegrationView
organization_id
provider
status
safe_status_reason
last_checked_at
can_manage
capabilities.directory_sync
secret_configured
last_sync
ContactIMProviderDefinition
provider
display_name
availability
unavailable_reason
auth_mode
callback_url
required_fields
ContactIMSyncRunView
id
status
started_at
started_by
completed_at
counts
safe_error
ContactIMSyncItemView
id
result
platform_identity
matched_contact
safe_reason
```
repository 暴露读取 integration/provider、保存配置、mock 授权、测试连接、解除绑定、启动同步、读取 active run 和分页读取详情等方法。mock 实现通过命名 scenario 或 seed 创建状态,所有延迟、错误和状态迁移必须确定且可在测试中控制,不能依赖随机数或不可控的真实计时。
后续真实后端就绪时,应新增实现相同 interface 的 API repository adapter,再由 composition root 切换依赖;页面组件和业务状态语义不应因此改写。
### 3. 使用共享绑定 shell 与 provider-specific form adapter
绑定 dialog / drawer 共享标题、状态、footer、错误反馈和 callback 区域;每个 provider 使用类型明确的 form adapter 处理自己的字段、帮助文案和认证方式。provider availability 和 capability 暂由 mock provider definition 提供。
不采用完全动态 JSON form renderer,因为 App ID、OAuth、callback、权限说明等交互差异较大;也不为每个 provider 复制完整 overlay,以避免状态和错误处理分叉。
### 4. 连接状态与 mutation 状态分层
`Not configured` 等六种状态来自 repository 中持久化的 mock integration state。`saving``testing``authorizing``disconnecting` 是短暂的前端 mutation state,不写入 connection status。
- 保存凭据成功后刷新 integrationmock repository 可将状态推进到 `Configured`
- 测试连接或 mock OAuth 结束后刷新 integration,由当前 scenario 决定最终六态。
- 所有 mutation pending 时阻止重复提交。
- 不做会伪造成功结果的 optimistic update。
### 5. Secret fixture 只表达配置状态,不保存真实 secret
已配置的 mock 数据只包含 `secret_configured: true` 或等价标识,不包含可回显 secret。用户输入新 secret 时,repository 只记录“已替换”的结果或版本标识,并立即丢弃原始文本;测试不得打印或快照 secret。
编辑非 secret 字段时使用字段省略或明确的 retain-secret command,掩码文本不得进入 mutation payload。
### 6. Mock sync run 使用 mutation 启动、query 恢复和有限 polling
启动同步 mutation 返回稳定的 `sync_run_id`。随后以该 ID 查询状态,只在 queued / running 时 polling;进入 success、partial success 或 failure 后停止 polling,并刷新 integration summary 和 detail query。
页面初始化时读取 mock active run。若 scenario 中存在进行中任务,UI 恢复该任务而不是创建新任务。mock repository 应允许测试通过 fake timers 或显式推进函数控制状态变化。
### 7. Sync details 以 `sync_run_id` 为稳定上下文
同步详情 surface 按 Figma 采用页面、drawer 或 dialog 的最终形态,但数据上下文必须由 `sync_run_id` 标识。推荐将该 ID 放入 URL query state,使刷新、返回和错误恢复不会丢失当前详情。
详情 query 支持 result filter 与 mock pagination。缺失 Email、Contact 或 platform name 时显示统一空值,不通过其他前端缓存猜测补全。
### 8. Summary 与 detail 使用统一结果 taxonomy
- `matched`:已匹配且 binding 无需修改。
- `created_binding`:创建新的 Contact IM binding。
- `updated_binding`:更新已有 Contact IM binding。
- `unmatched`:无法映射到 Contact,留待人工处理。
- `skipped`:因重复、缺少必要字段或规则明确忽略。
- `failed`:单条处理发生错误。
任务级状态与条目级分类分开:有成功条目同时也有 unmatched、skipped 或 failed 时,任务 UI 显示 partial success。
### 9. 权限和 provider gate 是 mock 展示状态,不是安全边界
入口 shell 根据 mock `can_manage` 和 provider capability 隐藏或禁用绑定、测试、同步和解除绑定操作,并展示相应解释。由于本 change 没有后端,权限场景只用于验收前端降级行为,不可被视为真实授权机制。
### 10. 使用 React Query、repository 与局部表单状态
- Integration、provider definitions、active sync 和 sync detail 通过 React Query 包装 repository 读取。
- 绑定表单草稿仅由 overlay 局部状态拥有,不引入新的全局 store。
- mutation 成功后按 query key 精确失效。
- overlay 使用 `@langgenius/dify-ui/*` primitives。
- mock repository 由 feature composition 层注入,生产构建不发出后端请求。
### 11. 测试围绕可观察状态机与替换边界
前端测试至少覆盖:
- 无绑定、已配置、已连接和三类错误状态。
- credential 与 mock OAuth 两种认证路径。
- secret 不回显、掩码不提交、更新时保留原 secret。
- 无权限、provider 不可用、保存 / 测试失败和重复提交。
- 同步按钮 gate、active run 恢复、polling 停止、成功 / 部分成功 / 失败摘要。
- 详情筛选、mock 分页、加载失败、unmatched 只读和敏感错误脱敏。
- 关键 overlay 的焦点恢复、键盘提交和错误关联。
- 页面只通过 repository interface 访问数据,替换 repository implementation 不改变组件 contract。
## Risks / Trade-offs
- [Mock shape 与未来 API 漂移] → 以 UI 所需 view model 为稳定边界;真实 adapter 负责映射后端 DTO,而不是让组件依赖后端 shape。
- [Mock 交互被误认为真实功能] → 入口使用 feature gate,并在交付说明中明确没有后端持久化、真实授权和真实同步。
- [Figma 中 provider-specific 差异可能继续调整] → 保留共享 shell 与 provider adapter 边界,将视觉差异限制在 adapter 内。
- [EE 与 CE / SaaS 入口不同导致重复实现] → shell 只注入 contextfeature 内容保持单一实现。
- [不可控 polling 造成测试不稳定] → mock 状态迁移使用 fake timers 或显式推进,不使用随机延迟。
- [大型详情 fixture 降低测试性能] → 用小型分页 fixture 验证增量加载,不生成大规模浏览器内数据。
- [Secret 泄露到 fixture 或快照] → fixture 只保存配置标记,repository 丢弃输入文本,测试断言日志与 DOM 中无 secret。
## Migration Plan
1. 建立 Contacts-owned view model、repository interface、query keys 和命名 mock scenarios。
2. 在 mock repository 上完成绑定、连接状态、手动同步与同步详情 UI。
3. 完成 Vitest / Testing Library 覆盖、Figma 对照、i18n、可访问性和前端 smoke。
4. 通过现有产品 feature gate 控制入口开放范围。
本 change 不包含数据迁移,也不要求任何后端部署步骤。回滚时关闭或移除前端入口即可。
后端能力就绪后另建 change:实现真实 contract 与 API repository adapter、补充服务端权限和 credential 安全,并将 composition root 从 mock 切换为真实 adapter。
## Open Questions
- 首个前端 mock 需要展示哪些 provider、认证方式和 directory sync capability,需在实现时依据 Figma 可见内容确定。
- 替换或解除 provider 的最终数据影响必须由后续 Contacts / IM 后端 contract 决定;当前 mock 只用于展示确认交互。
- Figma 中 callback、权限说明和 provider 帮助链接的最终文案,需要在实现阶段通过已授权的 Figma 访问核对。
@@ -0,0 +1,36 @@
## Why
Contacts 目前缺少用于配置 Organization 级 IM platform、触发通讯录同步以及排查同步结果的完整管理界面,管理员无法在产品内完成从“绑定渠道”到“确认联系人映射结果”的闭环。设计稿已经定义了绑定与同步详情的主要交互,需要将其整理为可实施、可验收的规格。
## What Changes
- 在 Contacts 管理区域增加 IM platform 管理入口,展示当前 provider、连接状态、最近同步信息和可执行操作。
- 提供首次绑定、补全配置、重新连接和更新配置的交互流程,并覆盖 provider 特定字段、表单校验、保存中状态与失败反馈。
- 将连接状态映射为 `Not configured``Configured``Connected``Permission issue``Callback error``Connection error`,为异常状态提供可排查原因和恢复入口。
- 支持由具备权限的管理员手动触发 IM 联系人同步,并展示同步进行中、成功、部分成功和失败状态。
- 增加同步详情视图,展示同步时间、发起人、结果汇总以及 matched、updated、unmatched、skipped、failed 等明细。
- 补齐权限受限、空数据、加载、重复提交、mock mutation 失败和重试等 UI 状态,并确保 secret 不被回显或写入前端日志。
- 本 change 只实现前端:所有展示与交互先通过集中、类型安全、可替换的 mock repository 驱动;真实后端 contract 与 API 接入留给后续独立 change。
- 以用户提供的六个 Figma 节点作为布局、文案层级和交互验收基准。
## Capabilities
### New Capabilities
- `contact-im-platform-binding`: 管理员在 Contacts 中查看 IM platform 状态、完成 provider 绑定或更新配置,并从异常状态恢复连接。
- `contact-im-directory-sync-details`: 管理员手动同步 IM 通讯录并查看一次同步的汇总、逐项匹配结果、异常原因和后续处理入口。
### Modified Capabilities
无。
## Impact
- 前端需要在 Contacts feature 边界内实现管理界面、相关路由、typed mock repository、dify-ui 组件使用和 `web/i18n/*` 文案。现有 `web/features/agent-v2/roster/` 管理的是可复用 AI Agent 资产,不属于本 change。
- 本 change 不修改后端 API、OpenAPI schema、生成式 client、数据模型、数据库迁移、任务队列、provider adapter 或真实 OAuth / credential 存储逻辑。
- 管理入口需要适配部署形态:EE 企业管理面与 CE / SaaS workspace 管理面复用同一 Contacts feature UI;角色权限、provider availability 和各类状态暂由 mock scenario 提供,仅用于前端行为展示,不构成安全边界。
- 需要为权限、连接状态、表单提交、手动同步、匹配结果和同步详情补充 Vitest / Testing Library 测试,并使用确定性的 mock scenario 完成前端 smoke 验证。
- 后续后端能力就绪时,应通过新的 change 用真实 repository adapter 替换 mock repository,而不改写页面组件的状态语义。
- 设计验收来源:
- 绑定界面:Figma nodes `1649:6572``1613:5906``1646:5214``1646:5959`
- 同步详情:Figma nodes `1634:5098``1634:5104`
@@ -0,0 +1,207 @@
## ADDED Requirements
### Requirement: Contacts 通讯录同步必须由管理员手动触发
前端 MUST 只允许 mock context 中具备管理权限的用户手动触发 Contacts IM directory sync。同步入口 MUST 仅在当前 IM platform 为 `Connected` 且 provider definition 声明支持通讯录读取时可用;本 capability MUST NOT 引入定时或自动同步。
#### Scenario: 已连接且支持通讯录同步
- **WHEN** 当前 provider 状态为 `Connected`、支持 directory sync,且 `can_manage` 为 true
- **THEN** 前端 MUST 启用手动同步操作
#### Scenario: Provider 尚未连接
- **WHEN** 当前 provider 未配置、仅为 `Configured` 或处于任一错误状态
- **THEN** 前端 MUST 禁用同步操作并提示先完成或修复连接
#### Scenario: Provider 不支持通讯录同步
- **WHEN** mock provider capability 声明不支持 directory sync
- **THEN** 前端 MUST 禁止触发同步并展示能力限制说明
#### Scenario: 普通用户尝试同步
- **WHEN** mock context 中无管理权限的用户进入同步区域
- **THEN** 前端 MUST 隐藏或禁用同步操作并展示权限说明
### Requirement: 同步 UI 必须只通过 typed mock repository 访问数据
本 change 中的同步 mutation、状态 query、摘要和详情 MUST 通过 Contacts-owned repository interface 访问 typed mock data。组件 MUST NOT 调用真实同步 API、真实 provider 或生成式 client。
#### Scenario: 启动 mock 同步
- **WHEN** 管理员点击同步
- **THEN** 前端 MUST 调用 repository mutation 并取得稳定的 mock `sync_run_id`
#### Scenario: 读取 mock 同步状态
- **WHEN** 页面展示 active run、最新摘要或指定 run 详情
- **THEN** 前端 MUST 通过 repository view model 读取数据,MUST NOT 直接 import 详情 fixture
#### Scenario: 确定性状态推进
- **WHEN** queued 或 running scenario 需要进入终态
- **THEN** repository MUST 使用 fake timers 或显式推进机制控制状态,MUST NOT 使用随机结果或不可控的真实延迟
#### Scenario: 前端同步不访问真实服务
- **WHEN** 任一同步交互运行
- **THEN** 当前 change MUST NOT 新增后端 endpoint、OpenAPI schema、任务队列或网络请求
### Requirement: 同一 Organization 不得重复启动并行 mock 同步
当前 Organization 已存在 queued 或 running 的 mock sync run 时,前端 MUST 连接到该任务的状态,MUST NOT 再创建重复任务。
#### Scenario: 启动新的同步
- **WHEN** 当前没有进行中的 run 且管理员点击同步
- **THEN** repository MUST 创建一次 mock run、返回其 identifier,并使 UI 进入进行中状态
#### Scenario: 重复点击同步
- **WHEN** 同步 mutation 或当前 run 仍在进行中
- **THEN** 前端 MUST 禁用重复触发并继续展示当前 run 状态
#### Scenario: 页面重新打开时已有同步
- **WHEN** 管理员重新打开 Contacts,而当前 scenario 已有 queued 或 running run
- **THEN** 前端 MUST 恢复该 run 的进度展示,MUST NOT 将其视为新的同步
### Requirement: UI 必须展示同步生命周期与最新摘要
前端 MUST 区分 queued、running、success、partial success 和 failure,并 MUST 展示 mock view model 提供的发起时间、发起人、完成时间或耗时、结果计数和安全错误摘要。同步状态 MUST 与 IM connection status 分开表达。
#### Scenario: 同步进行中
- **WHEN** mock run 为 queued 或 running
- **THEN** 前端 MUST 展示进行中状态,并按受控间隔读取该 run
#### Scenario: 同步全部成功
- **WHEN** mock run 完成且没有 unmatched、skipped 或 failed 结果
- **THEN** 前端 MUST 展示 success、完成时间和结果汇总
#### Scenario: 同步部分成功
- **WHEN** mock run 完成且同时包含成功结果与 unmatched、skipped 或 failed 结果
- **THEN** 前端 MUST 展示 partial success,并引导管理员查看同步详情
#### Scenario: 同步失败
- **WHEN** scenario 将 run 推进为 failure
- **THEN** 前端 MUST 展示安全错误原因和重试入口,同时保留上一次已完成 run 的可查看结果
#### Scenario: 同步到达终态
- **WHEN** queued 或 running run 进入任一终态
- **THEN** 前端 MUST 停止 polling,并刷新 integration summary 和当前 run 详情
### Requirement: 同步摘要必须区分联系人匹配结果
前端 MUST 使用同一个 mock sync run 的计数展示 matched、created binding、updated binding、unmatched、skipped 和 failed。前端 MUST NOT 将不同 run 的结果拼接为同一次摘要。
#### Scenario: 展示同步结果计数
- **WHEN** 一次 mock run 已返回结果摘要
- **THEN** 前端 MUST 展示该 run 各结果分类的计数与总量
#### Scenario: 结果计数为零
- **WHEN** 某个结果分类的计数为零
- **THEN** 前端 MUST 以明确零值或设计指定的省略规则展示,MUST NOT 将其显示为未知错误
#### Scenario: 计数与详情不一致
- **WHEN** 开发 fixture 中的摘要计数与当前 run 详情不一致
- **THEN** mock scenario validation SHOULD 使测试失败,避免把自相矛盾的数据交给 UI
### Requirement: 同步详情必须提供逐项、可排查的匹配信息
前端 MUST 允许管理员打开指定 `sync_run_id` 的详情。每条 mock 结果 MUST 在数据可用时展示 IM platform identity 的显示名、Email、platform user ID、匹配到的 Contact、结果分类和安全原因;缺失字段 MUST 使用明确空值表达,不得伪造数据。
#### Scenario: 已匹配 Contact
- **WHEN** mock platform member 已匹配到 Contact
- **THEN** 详情 MUST 展示 platform identity、目标 Contact 以及 matched、created binding 或 updated binding 结果
#### Scenario: 未匹配 platform member
- **WHEN** mock platform member 未命中 binding 或 Contact
- **THEN** 详情 MUST 将其标记为 unmatchedMUST NOT 表示系统已自动创建 External contact
#### Scenario: 跳过条目
- **WHEN** mock item 因缺少必要字段、重复或规则明确忽略而被跳过
- **THEN** 详情 MUST 展示 skipped 状态和安全原因
#### Scenario: 单条处理失败
- **WHEN** mock item 的 result 为 failed
- **THEN** 详情 MUST 展示 failed 状态和可排查原因,同时保留其他成功条目
#### Scenario: 通过 URL 恢复详情
- **WHEN** URL query 中包含有效 `sync_run_id`
- **THEN** 前端 MUST 恢复该 run 的详情上下文
### Requirement: 同步详情必须支持结果筛选与 mock 分页
前端 MUST 支持按结果分类查看同步条目,并 MUST 使用 repository 提供的分页或等价增量加载方式展示详情。筛选、分页和重试 MUST 始终绑定到当前 `sync_run_id`
#### Scenario: 按 unmatched 筛选
- **WHEN** 管理员选择 unmatched 分类
- **THEN** 前端 MUST 只读取或展示当前 run 中的 unmatched 条目
#### Scenario: 加载更多同步条目
- **WHEN** 当前分类还有下一页 mock 结果
- **THEN** 前端 MUST 允许增量加载且不得重复已有条目
#### Scenario: 详情分页失败
- **WHEN** scenario 使后续页读取失败
- **THEN** 前端 MUST 保留已加载条目并提供针对当前页的重试操作
#### Scenario: 切换筛选项
- **WHEN** 管理员从一个结果分类切换到另一个分类
- **THEN** 前端 MUST 重置该分类的分页游标,且 MUST NOT 混入上一分类的条目
### Requirement: Unmatched 结果必须保持 Contacts 领域语义
前端 MUST 将 unmatched 结果作为待后续人工处理的同步事实展示。同步详情 MUST NOT 自动创建 External contact,也 MUST NOT 在没有明确后续 capability 的情况下修改 Contact 或 IM Binding。
#### Scenario: 查看 unmatched 详情
- **WHEN** 管理员打开 unmatched 条目
- **THEN** 前端 MUST 展示 platform identity 和未匹配原因,MUST NOT 自动改变任何 Contacts 数据
#### Scenario: 后续处理能力尚未提供
- **WHEN** 当前版本没有手动映射或忽略 unmatched 的 capability
- **THEN** 前端 MUST 将详情保持为只读,MUST NOT 展示无法完成的伪操作
### Requirement: 同步 UI 必须安全、可访问且可恢复
前端和 mock fixture MUST 避免在同步摘要、详情、日志、错误反馈或测试快照中暴露 provider credential。用户可见文案 MUST 国际化,关键状态与操作 MUST 能被辅助技术识别。
#### Scenario: Mock 错误包含敏感诊断文本
- **WHEN** scenario 构造的原始错误包含 credential 或敏感 request detail
- **THEN** repository MUST 只向 view model 暴露经过安全处理的错误摘要
#### Scenario: 同步详情加载失败
- **WHEN** 指定 mock run 的详情读取失败
- **THEN** 前端 MUST 展示错误与重试操作,并 MUST 保留可用的同步摘要
#### Scenario: 辅助技术读取状态变化
- **WHEN** run 从 queued 进入 running 或终态
- **THEN** 前端 MUST 以不会造成重复噪声的可访问方式通知关键状态变化
#### Scenario: 关闭同步详情后恢复焦点
- **WHEN** 管理员关闭同步详情 drawer 或 dialog
- **THEN** 前端 MUST 将焦点恢复到打开详情的触发控件
@@ -0,0 +1,202 @@
## ADDED Requirements
### Requirement: Contacts 必须提供 Organization 级 IM platform 绑定入口
前端 MUST 在 Contacts 管理区域展示当前 Organization 的 IM platform 绑定状态与管理入口。该入口只用于联系人目录、联系人 IM identity 与通讯录同步,MUST NOT 被解释为 Agent、App 或 workflow 的渠道绑定。
#### Scenario: 尚未绑定 IM platform
- **WHEN** 具备 mock 管理权限的用户打开 Contacts,且当前 scenario 没有 IM platform 配置
- **THEN** 前端 MUST 展示未绑定状态和开始绑定操作
#### Scenario: 已绑定 IM platform
- **WHEN** 当前 scenario 已有 IM platform 配置
- **THEN** 前端 MUST 展示 provider、连接状态、最近检查信息、最近同步摘要以及当前可执行操作
#### Scenario: Agent Roster 不承载该入口
- **WHEN** 用户浏览可复用 AI Agent 的 Agent Roster
- **THEN** 前端 MUST NOT 在该列表中展示或管理本 capability 的联系人 IM platform 绑定
### Requirement: 绑定 UI 必须只通过 typed mock repository 访问数据
本 change 中的绑定页面、query 和 mutation MUST 通过 Contacts-owned repository interface 访问类型安全的 mock 数据。组件 MUST NOT 直接 import 零散 fixture、调用真实 IM provider、调用后端 API 或依赖生成式 API client。
#### Scenario: 初始读取绑定状态
- **WHEN** 绑定页面初始化
- **THEN** 前端 MUST 通过 repository 读取 integration、provider definition、permission 和 capability view model
#### Scenario: 切换验收场景
- **WHEN** 测试或开发预览选择一个命名 mock scenario
- **THEN** repository MUST 确定性返回该场景对应的状态、错误和可执行操作
#### Scenario: 未来替换数据实现
- **WHEN** 后续 change 提供真实 API repository adapter
- **THEN** 页面组件的 props、query keys 和业务状态语义 SHOULD 无需改写即可切换 adapter
#### Scenario: 前端操作不访问真实服务
- **WHEN** 用户保存、测试、授权、替换或解除绑定
- **THEN** 当前 change 的实现 MUST 只调用 mock repositoryMUST NOT 新增后端 endpoint、OpenAPI schema 或网络请求
### Requirement: 管理入口必须展示部署形态与权限差异
前端 MUST 支持 EE 企业管理面和 CE / SaaS workspace 管理面的 Contacts IM platform 入口。EE scenario 由企业管理员管理;CE / SaaS scenario 由 workspace owner 或 workspace admin 管理。该权限结果 MUST 来自 mock context,且 MUST 被明确视为 UI 展示状态而非真实安全边界。
#### Scenario: EE 企业管理员管理绑定
- **WHEN** EE 企业管理员 scenario 从企业 Contacts 管理面进入 IM platform 设置
- **THEN** 前端 MUST 允许其查看和操作当前 Organization 的 mock 绑定
#### Scenario: CE 或 SaaS 管理员管理绑定
- **WHEN** CE / SaaS workspace owner 或 workspace admin scenario 从 workspace Contacts 管理面进入 IM platform 设置
- **THEN** 前端 MUST 允许其查看和操作当前 Organization 的 mock 绑定
#### Scenario: 无管理权限
- **WHEN** 当前 mock context 的 `can_manage` 为 false
- **THEN** 前端 MUST 隐藏或禁用写操作,并 MUST 展示明确的权限说明
#### Scenario: 权限状态读取失败
- **WHEN** mock repository 返回权限读取失败
- **THEN** 前端 MUST 展示专用错误和重试操作,MUST NOT 将其降级为 `Not configured`
### Requirement: 同一 Organization 同时只能展示一个 active IM platform
前端 MUST 将当前 Organization 的 IM platform 作为单选绑定能力管理。已有 mock 绑定时,前端 MUST 展示该 provider 的配置,MUST NOT 在未确认替换或解除现有绑定的情况下创建第二个 active provider。
#### Scenario: 首次选择 provider
- **WHEN** 当前 scenario 尚未配置 IM platform,且管理员选择一个可用 provider
- **THEN** 前端 MUST 打开该 provider 对应的绑定流程
#### Scenario: 已有 active provider
- **WHEN** 当前 scenario 已绑定一个 provider
- **THEN** 前端 MUST 将该 provider 作为当前唯一 active binding 展示
#### Scenario: 替换 provider
- **WHEN** 管理员尝试将当前 provider 替换为另一个 provider
- **THEN** 前端 MUST 在执行 mock mutation 前要求确认,并 MUST 展示 scenario 提供的影响说明
### Requirement: 绑定流程必须适配 mock provider definition
前端 MUST 根据 typed mock provider definition 展示可用 provider、认证方式、必填字段、callback 信息和能力说明。凭据型 provider MUST 使用 provider-specific 表单;OAuth 型 provider MUST 使用可控的 mock 授权流程。
#### Scenario: 配置凭据型 provider
- **WHEN** 管理员选择使用 App ID、App Secret 或同类凭据的 provider
- **THEN** 前端 MUST 展示该 provider 所需字段、必填校验、帮助说明和可复制的 callback 信息
#### Scenario: 配置 OAuth 型 provider
- **WHEN** 管理员选择 OAuth 型 provider 并开始授权
- **THEN** 前端 MUST 进入 mock authorization pending 状态,并在 scenario 返回后刷新 repository 中的绑定状态
#### Scenario: Provider 当前不可用
- **WHEN** mock provider definition 将某个 provider 标记为未发布、不受当前部署支持或缺少必要能力
- **THEN** 前端 MUST 禁止开始该 provider 的绑定,并 MUST 展示可理解的不可用原因
#### Scenario: 必填字段缺失
- **WHEN** 管理员提交凭据表单但缺少 provider 要求的字段
- **THEN** 前端 MUST 阻止 mutation 并在对应字段附近展示校验信息
### Requirement: Secret 必须在 mock 绑定 UI 中保持不可回显
前端和 mock fixture MUST NOT 保存、返回或预填可回显的真实 secret。已有绑定只能通过 `secret_configured` 或等价状态表达。若管理员未提供替换值,前端 MUST NOT 把掩码或占位符作为新 secret 传给 repository。
#### Scenario: 打开已有绑定配置
- **WHEN** 管理员打开一个已配置 App Secret 的 mock provider
- **THEN** DOM、fixture、日志、错误反馈和测试快照 MUST NOT 包含原 secret
#### Scenario: 更新非 secret 字段
- **WHEN** 管理员只修改非 secret 字段并保留原 secret
- **THEN** 前端 MUST 省略替换值或发送 typed retain-secret commandMUST NOT 发送掩码文本
#### Scenario: 替换 secret
- **WHEN** 管理员显式输入新的 secret 并执行保存
- **THEN** mock repository MUST 只记录“secret 已替换”的状态并立即丢弃输入文本,提交完成后 UI MUST 恢复为不可回显状态
### Requirement: UI 必须完整表达六种 IM connection status
前端 MUST 使用 mock repository state 区分 `Not configured``Configured``Connected``Permission issue``Callback error``Connection error`。错误状态 MUST 展示可安全公开的原因、最近检查时间以及适用的恢复操作。
#### Scenario: 配置已保存但尚未验证
- **WHEN** mock provider 配置已保存但尚未完成连接测试
- **THEN** 前端 MUST 展示 `Configured`MUST NOT 将其误报为 `Connected`
#### Scenario: Mock 连接测试成功
- **WHEN** 当前 scenario 的测试连接 mutation 成功
- **THEN** repository MUST 将状态推进为 `Connected`,前端 MUST 刷新并展示新的可用操作
#### Scenario: Provider 权限不足
- **WHEN** repository 返回 `Permission issue`
- **THEN** 前端 MUST 展示缺失权限或修复指引,并 MUST 提供重新测试或更新配置入口
#### Scenario: Callback 配置异常
- **WHEN** repository 返回 `Callback error`
- **THEN** 前端 MUST 展示 callback 相关原因和可复制的正确 callback 信息
#### Scenario: 其他连接失败
- **WHEN** repository 返回 `Connection error`
- **THEN** 前端 MUST 展示安全的失败原因和重试入口,MUST NOT 暴露凭据
### Requirement: 保存、测试、更新与解除绑定必须防止重复操作
前端 MUST 为保存配置、mock 测试连接、更新配置、替换 provider 和解除绑定提供明确的 pending、成功与失败状态。操作进行中 MUST 防止重复 mutation;失败时 MUST 保留可安全保留的表单内容,并通过重新读取 repository 确认最终状态。
#### Scenario: 保存进行中
- **WHEN** mock 保存 mutation 尚未结束
- **THEN** 前端 MUST 禁用会产生重复写入的操作并展示进行中状态
#### Scenario: 保存失败
- **WHEN** scenario 配置保存 mutation 失败
- **THEN** 前端 MUST 保持表单可继续修正,展示安全失败原因,MUST NOT 乐观展示成功状态
#### Scenario: 测试连接
- **WHEN** 管理员触发 mock 测试连接
- **THEN** 前端 MUST 防止并发重复测试,并 MUST 在 mutation 结束后重新读取 connection status
#### Scenario: 解除绑定
- **WHEN** 管理员确认解除当前 IM platform 绑定,且 mock mutation 成功
- **THEN** 前端 MUST 展示 `Not configured` 并关闭新的通讯录同步入口
### Requirement: 绑定 UI 必须具备完整的基础交互状态
前端 MUST 为初始加载、加载失败、空状态、表单错误、权限受限和操作成功提供可访问且国际化的反馈。用户可见文案 MUST 使用项目 i18n 资源,交互控件 MUST 支持键盘操作与可辨识的 focus 状态。
#### Scenario: 初始数据加载失败
- **WHEN** mock repository 返回 Contacts IM platform 状态加载失败
- **THEN** 前端 MUST 展示错误状态和重试操作,MUST NOT 将失败误显示为未绑定
#### Scenario: 键盘完成绑定
- **WHEN** 管理员只使用键盘浏览 provider、填写表单并提交
- **THEN** 前端 MUST 保持合理的焦点顺序、可见焦点和可读错误关联
#### Scenario: Overlay 关闭后恢复焦点
- **WHEN** 管理员关闭 binding dialog 或 drawer
- **THEN** 前端 MUST 将焦点恢复到打开该 overlay 的触发控件
@@ -0,0 +1,36 @@
## 1. Frontend Scope and Design Baseline
- [ ] 1.1 Identify the EE enterprise-management and CE / SaaS workspace-management mount points for Contacts, define the shared Organization context contract, and verify that no entry is added under `web/features/agent-v2/roster/`.
- [ ] 1.2 Inspect the six referenced Figma nodes with authorized access and record a frontend acceptance matrix for layout, overlay type, fields, statuses, table columns, responsive behavior, and visible copy.
- [ ] 1.3 Define the existing product feature gate used to expose the mock-backed Contacts IM platform entry and its rollback behavior.
## 2. Typed Mock Data Boundary
- [ ] 2.1 Write failing unit tests for repository scenario consistency, single-active-provider behavior, deterministic state transitions, summary/detail count agreement, and secret sanitization.
- [ ] 2.2 Add Contacts-owned TypeScript view models, command types, repository interface, query keys, and typed result taxonomy for integration, provider definitions, sync runs, and sync items.
- [ ] 2.3 Implement named deterministic mock scenarios covering loading, load failure, no permission, provider unavailable, all six connection states, mutation failures, active sync, success, partial success, failure, detail failure, and paginated results.
- [ ] 2.4 Implement the in-memory mock repository so mutations update only mock state, queued/running transitions are controllable with fake timers or explicit advancement, and secret input is discarded after recording configuration state.
- [ ] 2.5 Add a feature composition boundary and React Query hooks that inject the repository, invalidate precise query keys after mutations, and make no backend or provider network requests.
## 3. IM Platform Binding UI
- [ ] 3.1 Write failing component tests for the Contacts entry, EE and CE / SaaS permission variants, initial loading/error/empty states, provider availability, and the six connection-status presentations.
- [ ] 3.2 Implement the shared Contacts IM platform management surface, status summary, provider selection, diagnostics, recent-sync summary, and feature-gated mount points with `@langgenius/dify-ui/*` primitives.
- [ ] 3.3 Write failing component tests for credential and mock OAuth flows, required-field errors, pending-state duplicate prevention, mutation failure recovery, provider replacement confirmation, and disconnect behavior.
- [ ] 3.4 Implement the shared binding overlay and typed provider-specific form adapters, including mock authorization recovery, callback copy interaction, replacement/disconnect confirmation, and repository refresh after mutations.
- [ ] 3.5 Write and satisfy security regression tests proving that configured secrets are represented only by a boolean/state marker and never appear in fixtures, DOM output, logs, snapshots, or retained mutation payloads.
## 4. Manual Directory Sync and Details UI
- [ ] 4.1 Write failing component and hook tests for sync eligibility, no-permission and unsupported-provider gates, duplicate-trigger prevention, active-run restoration, controlled polling, and polling termination at every terminal state.
- [ ] 4.2 Implement the manual sync trigger, queued/running presentation, success/partial-success/failure summaries, latest completed result retention, and targeted query refresh behavior.
- [ ] 4.3 Write failing component tests for `sync_run_id` URL restoration, result taxonomy and counts, missing-field placeholders, unmatched read-only behavior, filters, pagination, page retry, and sensitive-error sanitization.
- [ ] 4.4 Implement the Figma-aligned sync details surface with run metadata, result summary, filter controls, incrementally loaded rows, per-item safe reasons, error recovery, and no Contact or IM Binding mutation actions.
## 5. Product Quality and Verification
- [ ] 5.1 Add all user-facing copy to `web/i18n/en-US/` and update every supported locale with correct localized values.
- [ ] 5.2 Match the authorized Figma acceptance matrix using dify-ui tokens, including loading and error states, responsive layouts, visible focus, keyboard submission, error associations, live status announcements, and focus restoration for overlays.
- [ ] 5.3 Run the targeted Vitest / Testing Library suites and resolve all failures, including fake-timer cleanup and React Query cache isolation between scenarios.
- [ ] 5.4 Run the repository-prescribed frontend formatting, lint, and type-check commands, then fix issues introduced by this change.
- [ ] 5.5 Audit the final diff to confirm it changes only frontend and OpenSpec files, adds no backend/OpenAPI/generated-client/task-queue code, issues no real IM or backend requests, and leaves the future API repository adapter for a separate change.