Files
MyAiDesk/nomifun-tauri/docs/feishu-integration-plan.md
freedak f7a720204a Update: 将子项目从 submodule 转为完整内容
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用
- 添加所有子项目的完整源代码
- 保留原始 .git 为 .git.bak 备份
2026-07-04 19:20:46 +08:00

60 KiB
Raw Permalink Blame History

NomiFun × 飞书 — 企业工作台集成落地方案

文档版本:v3.4
日期:2026-07-02
状态:方案评估(基于代码库深度验证 + 飞书 API 文档验证)
变更:v3.0 — 审批流程改为人工执行(AI 仅辅助查询,人在工作台 UI 操作);新增企业经营看板模块
变更:v3.1 — 落地模式优化:审批 UI 采用混合模式(原生列表/详情 + 飞书 JS SDK 表单);经营看板独立页面优先(打开即看)+ AI 对话深度查询;分阶段交付,首个可用版本提前至 10-16 天
变更:v3.2 — 代码库二次验证修正:recharts 尚未安装(需新增依赖);前端路径修正为 ui/src/renderer/pages/;新增 Tauri 深链配置、飞书 JS SDK SSO 流程、数据表 Schema、错误降级策略、测试策略;澄清卡片按钮机制与 CallerCtx 角色映射链路;修正飞书卡片 chart 工作量评估
变更:v3.3 — 关键可行性修正:飞书 H5 JS SDK 仅在飞书客户端内可用,Tauri webview 不可用;审批写操作是服务端 REST API 非 JS SDK 方法;OAuth redirect_uri 改为本地 HTTP 回调方案;审批 UI 回归原生模式(React + Arco Form 动态渲染);工作量相应调整
变更:v3.4 — 审批方案简化:改用飞书 AppLink 跳转模式,NomiFun 只做查询/展示,审批写操作跳转飞书客户端完成。消除 OAuth/动态表单/后端写代理三大复杂度,Phase 1b 从 10-15 天降至 5-7 天。新增 tauri-plugin-opener 依赖


一、方案总览

1.1 核心命题

组织架构、审批流程、文档知识库全部托管在飞书平台,企业经营数据由数据中台加工完成。NomiFun 作为统一工作台,通过以下能力整合调用:

  • 消息通道:飞书 Bot 作为 NomiFun 的统一交互入口(自然语言 → AI 理解 → 工具调用)
  • MCP 工具总线:将飞书通讯录、审批查询、数据中台 API 封装为标准 MCP 工具,AI Agent 自动编排调用
  • 审批辅助(非执行)AI 仅查询审批状态、辅助填表预览;审批的创建、同意、拒绝通过 AppLink 跳转飞书客户端由人完成,AI 不执行任何审批动作
  • 审批 UI AppLink 跳转模式:列表/详情用原生 React 组件(轻量、UX 一致),写操作通过 AppLink 跳转飞书客户端完成(复用飞书原生表单引擎,零维护)
  • 知识库同步:飞书 Wiki 空间文档增量同步为本地 Markdown 快照,供 AI 检索
  • 经营看板:从数据中台获取已加工的经营指标,按用户角色/部门展示差异化看板。独立看板页面(打开即看)+ AI 自然语言对话(深度查询/下钻/对比)双模式
  • 飞书卡片即看板:经营数据查询结果也可通过飞书卡片 chart 组件渲染,在聊天中直接查看
  • Webhook 通知:任务完成/审批状态变更通过飞书自定义机器人卡片推送到群/个人

1.2 架构全景图

┌──────────────────────────────────────────────────────────────┐
│                        飞书 (Lark)                            │
│  通讯录 │ 审批流程 │ Wiki 文档 │ 消息/卡片 │ 事件订阅          │
└────┬─────────┬──────────┬──────────┬──────────┬───────────────┘
     │         │          │          │          │
     ▼         ▼          ▼          ▼          ▼
  ┌──────────────────────────────────────────────────────────┐
  │              NomiFun Rust Backend                        │
  │                                                          │
  │  ┌────────────┐  ┌─────────────┐  ┌──────────────────┐  │
  │  │ Lark       │  │ Feishu      │  │ MCP 工具总线     │  │
  │  │ Channel    │  │ Connector   │  │ (Registry)       │  │
  │  │ Plugin     │  │ (知识库)    │  │                  │  │
  │  │            │  │             │  │ 已有 132+ 工具   │  │
  │  │ WebSocket  │  │ 增量同步    │  │ + 新增飞书域:    │  │
  │  │ 事件接收   │  │ 快照→MD    │  │  - feishu_org_*  │  │
  │  │ 消息发送   │  │             │  │  - feishu_appr_* │  │
  │  │ 卡片交互   │  │             │  │  - dashboard_*   │  │
  │  └─────┬──────┘  └──────┬──────┘  └────────┬─────────┘  │
  │        │                │                  │            │
  │  ┌─────▼──────────────────────────────────▼─────────────┐  │
  │  │           AI Agent Engine (nomi)                     │  │
  │  │    自然语言理解 → 工具选择 → 执行 → 结果整合         │  │
  │  │    工具审批门控 (DangerTier × Surface)               │  │
  │  │    ⚠ 审批操作不经过 AI — 仅查询/辅助,人在飞书客户端操作  │  │
  │  └──────────────────────────────────────────────────────┘  │
  │                                                          │
  │  ┌──────────────────────────────────────────────────┐   │
  │  │  数据中台对接 (caps_dashboard.rs)                 │   │
  │  │  外部 API ← 已加工经营指标 · 角色化数据过滤       │   │
  │  └──────────────────────────────────────────────────┘   │
  │  ┌──────────────────────────────────────────────────┐   │
  │  │         Webhook 通知服务                          │   │
  │  │    飞书自定义机器人卡片 + HMAC-SHA256 签名        │   │
  │  └──────────────────────────────────────────────────┘   │
  │  ┌──────────────────────────────────────────────────┐   │
  │  │  审批工作台 UI (AppLink 跳转模式)                 │   │
  │  │  原生: 列表/详情/时间线 (React + Arco)            │   │
  │  │  写操作: AppLink 跳转飞书客户端 (tauri-opener)    │   │
  │  └──────────────────────────────────────────────────┘   │
  │  ┌──────────────────────────────────────────────────┐   │
  │  │  经营看板前端 (React + Arco Design + recharts)    │   │
  │  │  角色化看板页面 · 指标卡片 · 趋势图表             │   │
  │  │  ⚠ recharts 需新增依赖(当前未安装)              │   │
  │  │  也通过飞书 Bot 卡片 chart 组件投递               │   │
  │  └──────────────────────────────────────────────────┘   │
  └──────────────────────────────────────────────────────────┘

二、现有基础设施评估(代码级验证)

2.1 飞书消息通道 — 已完整实现

文件: crates/backend/nomifun-channel/src/plugins/lark/plugin.rs

能力 状态 实现位置 说明
WebSocket 长连接 已实现 start() 方法 通过飞书 SDK 获取 WS endpoint,自动重连
消息接收 已实现 handle_message_event() 解析 im.message.receive_v1 事件,转换为 UnifiedIncomingMessage
事件去重 已实现 event_id 去重窗口 防止飞书重推导致重复处理
文本/富文本发送 已实现 send_message() 支持纯文本和富文本
交互卡片发送 已实现 send_card() 调用 api.rs 的卡片消息接口
卡片更新 已实现 update_card() 用于审批状态变更后刷新卡片
卡片按钮回调 已实现 card_action_trigger 事件处理 用户点击卡片按钮 → 回调路由
Bot 菜单事件 已实现 bot_menu_event 处理 飞书机器人菜单点击
用户配对授权 已实现 ActionExecutor::handle_incoming_message() 飞书 open_id → 内部 user_id 映射

消息路由链路(已验证):

飞书 WebSocket 事件
  → LarkPlugin::handle_message_event()          // 解析为 UnifiedIncomingMessage
  → mpsc::Sender → ChannelManager forwarder      // 加盖 channel_id
  → ChannelOrchestrator::handle_message()        // 异步 spawn
  → ActionExecutor::handle_incoming_message()    // 授权检查 + 路由
    → MessageResult::Dispatched                  // 文本消息 → AI 会话
    → MessageResult::Action                      // 按钮回调 → 动作执行
  → ChannelMessageService → AI Agent 引擎        // 进入 nomi agent 工具调用循环

关键发现: 消息从飞书到 AI Agent 的完整链路已经打通,无需新增代码。配置飞书自建应用即可使用。

2.2 飞书知识库 Connector — 已完整实现

文件: crates/backend/nomifun-knowledge/src/connector_feishu.rs

能力 状态 实现细节
Token 管理 tenant_access_token 获取 + 30min 缓存 + 401 自动刷新
限流 4 QPS (250ms 间隔) + 429 重试 (x-ogw-ratelimit-reset)
Wiki 空间节点列表 /open-apis/wiki/v2/spaces/{space_id}/nodes 分页拉取
增量同步 SyncCursor.last_sync_at 游标,跳过未修改文档
文档块 → Markdown feishu_md::blocks_to_markdown() 转换
快照持久化 写入 snapshots/ 目录,YAML frontmatter 含 source_url
凭证验证 validate_credentials() → 获取 token 验证有效性
测试覆盖 wiremock 集成测试 8 个用例(token 缓存/分页/增量/错误码)

Connector trait 架构:

// crates/backend/nomifun-knowledge/src/connector.rs
trait KnowledgeConnector {
    fn kind(&self) -> &'static str;                    // "feishu"
    async fn validate_credentials(...) -> ConnectorIdentity;
    async fn list_documents(...) -> SyncPage;          // 分页 + 增量
    async fn fetch_document(...) -> FetchedConnectorDoc; // blocks → markdown
    async fn subscribe_webhook(...) -> Option<...>;     // 预留(当前 poll-only
    async fn push_document(...) -> Result<...>;         // 预留(未来双向同步)
}

同步编排(已验证): KnowledgeService::sync_connector_source() 执行两阶段同步:

  1. Phase 1: 分页 list_documents,收集文档引用 + 墓碑(删除标记)
  2. Phase 2: 逐个 fetch_document → 压缩 → 写入快照文件

限制: 当前仅同步 docx 类型文档(obj_type == "docx" 过滤),不支持 Sheet/Bitable/Mindnote。

2.3 MCP 工具总线 — 已完整实现

文件: crates/backend/nomifun-gateway/src/registry/

工具注册体系:

Registry::build()  →  逐域 register()
  ├── caps_memory          (记忆)
  ├── caps_conversation    (会话管理)
  ├── caps_requirement     (需求管理)
  ├── caps_autowork        (自动化工作)
  ├── caps_knowledge       (知识库搜索)
  ├── caps_channel         (IM 通道管理)
  ├── caps_agent           (Agent 委托)
  ├── caps_terminal        (终端)
  ├── caps_files           (文件)
  ├── caps_mcp             (MCP 管理)
  ├── ... 共 18 个域, 132+ 个工具
  ├── caps_feishu_org (待新增)     ← 飞书组织架构 (Read)
  ├── caps_feishu_approval (待新增) ← 飞书审批查询 (Read only, 人在飞书客户端操作)
  └── caps_dashboard (待新增)      ← 经营看板 (Read, 对接数据中台)

权限矩阵(已验证,关键约束):

Surface Read Write Destructive Sensitive
Desktop Allow Allow Confirm Confirm
Channel Allow Allow Deny Deny
Remote Allow Allow Confirm Deny

⚠️ 关键发现: 飞书消息触发的 AI 会话走 Surface::Channel。在该 Surface 下:

  • Read 级别工具 自动放行 — 适合审批查询、组织架构查询、经营看板查询
  • Write 级别工具 自动放行 — 但审批操作不封装为工具,避免 AI 越权
  • DestructiveSensitive 级别工具 硬拒绝 — 即使 confirm=true 也不行
  • 可通过 deny_on / confirm_on 覆盖特定 Surface 行为

工具定义模式(已验证):

// 新增工具只需:
// 1. 创建 caps_feishu.rs,定义参数 struct + handler
// 2. 在 lib.rs 添加 mod caps_feishu;
// 3. 在 Registry::build() 添加 crate::caps_feishu::register(&mut caps);

Capability::new(
    CapabilityMeta::new(
        "nomi_feishu_org_search",    // 工具名,≤42 字符
        "feishu",                     // 域标签
        "Search employees in Feishu contacts", // LLM 可见描述
        DangerTier::Read,             // 读操作 → Channel Surface 放行
    ),
    |deps, ctx, params| async move {
        // handler 逻辑
        json!({ "results": [...] })
    },
)

2.4 Webhook 通知 — 已完整实现

文件: crates/backend/nomifun-webhook/src/sender.rs

能力 状态 说明
飞书自定义机器人卡片 支持 interactive card JSON payload
HMAC-SHA256 签名 按飞书规范签名,timestamp + key
Slack 格式 兼容
通用 HTTP JSON 兜底
Webhook CRUD 管理 service.rs 完整 CRUD + 标签绑定
事件绑定 tag-based event bindingAutoWork 可触发

2.5 AI Agent 工具调用链路 — 已完整实现

完整调用链路(已验证):

用户在飞书发送消息
  → LarkPlugin → ChannelOrchestrator → ActionExecutor
  → ChannelMessageService → AI Agent (nomi)
  → LLM 识别意图,返回 tool_use (ContentBlock::ToolUse)
  → orchestration.rs::execute_tool_calls_with_approval()
    → ToolConfirmer / ToolApprovalManager 审批门控
    → registry.get(name).execute(input) → McpToolProxy
    → McpManager::call_tool(server_name, tool_name, input)
    → stdio bridge → GatewayMcpServer (HTTP)
    → Registry::global().dispatch_opt(deps, ctx, name, args)
    → Capability.handler(deps, ctx, params) → 实际执行
    → 结果返回 → LLM 整合 → 飞书消息回复

审批门控(已验证):

  • ToolCategory::Info(readOnly)→ 自动批准,可并发执行
  • ToolCategory::Exec(mutating)→ 需要用户批准(除非 auto_approve 或 allow_list
  • 飞书 Channel Surface 额外受 DangerTier 矩阵约束

三、新增工作:飞书 OA 工具域 + 经营看板

3.1 模块划分

模块 文件 工具数 DangerTier 工作量
组织架构 caps_feishu_org.rs 3 Read 3-5 天
审批查询(仅读) caps_feishu_approval.rs 3 Read 3-4 天
审批列表/详情 UI(原生) ui/src/renderer/pages/approval/ - - 3-4 天
审批写操作(AppLink 跳转) OpenInFeishuButton.tsx + tauri-plugin-opener - - 1 天
经营看板 MCP 工具 caps_dashboard.rs 4 Read 5-8 天
看板前端页面 ui/src/renderer/pages/dashboard/ - - 6-10 天
飞书卡片 chart 投递 扩展 sender.rs - - 2-3 天
卡片交互路由 扩展 action.rs - - 1-2 天
Tauri 深链(已有)+ Opener 插件 tauri.conf.json(已有)+ Cargo.toml 新增 - - 1 天
数据表 migration nomifun-db/migrations/ - - 1 天
定时同步调度 扩展 services.rs - - 1-2 天
权限感知搜索 扩展 knowledge_tools.rs - - 3-5 天

💡 v3.4 方案变更: v3.2 的「飞书 JS SDK 混合模式」不可行(H5 SDK 仅在飞书客户端内可用);v3.3 的原生模式虽可行但复杂度高(动态表单 + OAuth + 后端写代理 = 10-15 天)。v3.4 改用 AppLink 跳转模式:NomiFun 负责查询和展示,审批写操作通过 AppLink 跳转飞书客户端完成。无需 OAuth、无需动态表单、无需后端写代理,工作量降至 3-5 天,且保留增量升级路径。

⚠️ 审批流程设计原则: AI 仅提供查询和辅助能力(查待办、查详情、辅助填表预览),审批的创建、同意、拒绝全部通过 AppLink 跳转飞书客户端由人完成。AI 不执行任何审批动作,确保审批责任链清晰,AI 不承担审批决策风险。

3.2 组织架构工具 (caps_feishu_org.rs)

飞书 API 对接:

工具名 飞书 API DangerTier 说明
nomi_feishu_org_search /open-apis/contact/v3/users/search Read 按姓名/部门搜索员工
nomi_feishu_org_dept_tree /open-apis/contact/v3/departments Read 获取部门树
nomi_feishu_org_user_detail /open-apis/contact/v3/users/{user_id} Read 员工详情(职位、上级、邮箱)

实现要点:

  1. 复用 FeishuConnector 的 token 管理: 将 connector_feishu.rs 中的 token_cache / rate_limit / authed_get 提取为公共 trait 或共享模块,避免重复实现
  2. 本地缓存: 飞书通讯录 API 有严格限流(10 QPS),需在 SQLite 中维护 org_cache 表,TTL 15 分钟
  3. PII 脱敏: 手机号/邮箱在返回给 LLM 前脱敏(138****1234),仅在用户明确请求时解敏
  4. 权限边界: 飞书 app 的通讯录可见范围 = NomiFun 可访问的数据边界

参数 struct 示例:

#[derive(Deserialize, JsonSchema)]
struct OrgSearchParams {
    /// 搜索关键词(姓名、拼音、工号)
    query: String,
    /// 限制返回数量,默认 10,最大 50
    #[serde(default = "default_page_size")]
    page_size: u32,
}

3.3 审批查询工具 (caps_feishu_approval.rs) — 仅查询,人在飞书客户端操作

设计原则: 审批流程全部通过 AppLink 跳转飞书客户端由人完成。AI 的角色是:

  1. 查询待办: "我有哪些待审批?"
  2. 查询详情: "这个审批的具体内容是什么?"
  3. 辅助填表: AI 根据用户描述生成表单预览,用户在飞书客户端中确认并提交
  4. 状态提醒: 审批状态变更时通过 Webhook 推送通知

飞书 API 对接(仅 Read:

工具名 飞书 API DangerTier 说明
nomi_feishu_appr_list /open-apis/approval/v4/tasks Read 查询待审批列表(按用户过滤)
nomi_feishu_appr_get /open-apis/approval/v4/instances/{instance_id} Read 查询审批详情(表单内容、审批节点、状态)
nomi_feishu_appr_templates /open-apis/approval/v4/approvals Read 查询可用审批模板及表单结构定义

不封装为 MCP 工具的操作(人在飞书客户端执行):

操作 原因 AppLink 跳转方式
创建审批实例 审批发起需人工确认 AppLink 打开飞书发起审批页 → 填写表单 → 提交
同意审批 审批决策必须由人做出 AppLink 打开飞书审批详情页 → 点击「同意」
拒绝审批 同上 AppLink 打开飞书审批详情页 → 点击「拒绝」

AI 辅助填表流程:

用户: "帮我发起请假,7月5号到7月7号,事假"

① AI 调用 nomi_feishu_appr_templates → 获取「请假申请」模板表单结构
② AI 根据用户描述填充表单字段 → 生成预览卡片
③ 飞书回复卡片: 表单预览 + 「在飞书中发起」按钮(AppLink URL
④ 用户点击 → AppLink 跳转飞书客户端审批发起页
⑤ 用户在飞书客户端中确认并提交审批

审批模板管理: 在 NomiFun 中维护 feishu_approval_templates 表:

  • approval_code ↔ 飞书审批定义 code
  • form_schema — JSON Schema 描述表单字段,供 AI 理解如何填充
  • display_name — 人类可读名称("请假申请"、"报销单"等)
  • applink_path — 飞书 AppLink 路径模板(如 pc/pages/create-form/index?id={approval_code}

设计原则: NomiFun 负责查询和展示(审批列表、详情预览、AI 辅助),审批写操作(创建/同意/拒绝)通过飞书 AppLink 跳转飞书客户端完成。AI 不参与审批操作。

⚠️ v3.4 方案变更: v3.3 的原生模式(动态表单 + OAuth + 后端写代理 = 10-15 天)虽可行但复杂度高。经飞书官方文档验证,飞书 AppLink 协议支持直接打开审批页面(发起/详情/审批中心),用户在飞书客户端中操作无需 OAuth。v3.4 改为 AppLink 跳转模式,大幅降低复杂度(3-5 天),且保留升级路径。

AppLink 跳转模式架构:

┌─────────────────────────────────────────────────────┐
│              NomiFun 工作台                          │
│                                                     │
│  ┌──────────────┐  ┌───────────────────────────┐   │
│  │ 审批列表/详情  │  │ AI 辅助填表预览             │   │
│  │ (原生 React)  │  │ (预填数据 → AppLink 传递)   │   │
│  │ 轻量·快速·一致 │  │ 跳转飞书完成实际提交         │   │
│  └──────┬───────┘  └───────────┬───────────────┘   │
│         │                      │                    │
│         │  MCP 查询工具         │ AppLink URL         │
│         │  (AI 辅助)            │ (tauri-plugin-opener)│
│         ▼                      ▼                    │
│  ┌──────────────────────────────────────────────┐   │
│  │    飞书审批 OpenAPI (v4) + AppLink             │   │
│  │  Read: 查询列表/详情/模板  → MCP 工具         │   │
│  │  Write: 创建/同意/拒绝     → AppLink 跳飞书    │   │
│  └──────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────┘

为什么 AppLink 跳转模式(v3.4:

维度 原生模式 (v3.3) AppLink 跳转 (v3.4)
OAuth 流程 需要(本地 HTTP 回调 + token 管理) 不需要(用户已在飞书登录)
动态表单 需要 Arco Form 动态渲染 不需要(飞书原生表单引擎)
后端写代理 需要 REST API 代理 不需要(飞书客户端直接调 API
user_access_token 需要获取和管理 不需要
工作量 10-15 天 3-5 天
UX 全程不离开 NomiFun 写操作需跳转飞书(一次跳转)
升级路径 - 可增量添加 OAuth + 写代理

飞书 AppLink 审批页面 URL:

// 打开审批详情页(同意/拒绝在飞书内完成)
https://applink.feishu.cn/client/mini_program/open
  ?appId=cli_9cb844403dbb9108
  &path=pages%2Fdetail%2Findex%3FinstanceId%3D${instanceId}

// 打开发起审批页
https://applink.feishu.cn/client/mini_program/open
  ?appId=cli_9cb844403dbb9108
  &path=pc%2Fpages%2Fcreate-form%2Findex%3Fid%3D${approvalCode}

// 打开审批中心(待办列表)
https://applink.feishu.cn/client/mini_program/open
  ?mode=appCenter
  &appId=cli_9cb844403dbb9108
  &path=pc%2Fpages%2Fin-process%2Findex

来源: 飞书官方文档 打开审批页面cli_9cb844403dbb9108 是飞书审批应用的固定 appId。

前端页面架构:

ui/src/renderer/pages/approval/
  ├── ApprovalListPage.tsx       // 审批待办列表(原生 React + Arco Table
  ├── ApprovalDetailPage.tsx     // 审批详情预览(原生:表单内容 + 时间线 + 「在飞书中处理」按钮)
  ├── components/
  │   ├── ApprovalTimeline.tsx   // 审批流程时间线(原生)
  │   └── OpenInFeishuButton.tsx // AppLink 跳转按钮(调用 tauri-plugin-opener
  └── hooks/
      └── useApprovalQuery.ts    // 调用 MCP 查询工具获取列表/详情

对比 v3.3: 无需 DynamicForm.tsxuseFeishuAuth.tsApprovalCreatePage.tsx——审批表单填写和提交在飞书客户端完成。

后端审批查询 API(MCP 工具,AI 和前端共用):

端点 方法 说明 MCP 工具
/api/approval/list GET 获取当前用户待审批列表 nomi_feishu_appr_list
/api/approval/:id GET 获取审批详情 nomi_feishu_appr_get
/api/approval/templates GET 获取可用审批模板 nomi_feishu_appr_templates

审批写操作(AppLink 跳转飞书客户端):

操作 方式 认证
创建审批 AppLink 打开飞书发起审批页 飞书客户端登录态
同意审批 AppLink 打开飞书审批详情页 飞书客户端登录态
拒绝审批 AppLink 打开飞书审批详情页 飞书客户端登录态

关键设计: 审批写操作通过 AppLink 跳转飞书客户端,用户在飞书中完成操作。不需要 OAuth不需要 user_access_token不需要后端写代理。AI Agent 无法触达审批写操作。

审批列表也可嵌入对话侧边栏: 复用 ChatSliderextraTabs 模式(参考 NomiSessionMetricsPanel),在对话侧边栏中嵌入审批待办列表,实现「边聊天边查看审批」。

升级路径: 若后续需要「全程不离开 NomiFun」,可增量添加:① OAuth(2-3 天)→ ② 后端写代理(3-5 天)→ ③ 动态表单(3-4 天)。每步独立,无需推翻重来。

3.4.1 Tauri 深链配置(nomifun:// 协议)

现状: 项目已配置 Tauri v2 深链插件,nomifun scheme 已注册(见 tauri.conf.json:38-42Cargo.toml:33)。

// apps/desktop/tauri.conf.json (已有配置)
"plugins": {
  "deep-link": {
    "desktop": {
      "schemes": ["nomifun"]
    }
  }
}
# apps/desktop/Cargo.toml (已有依赖)
tauri-plugin-deep-link = "2"
tauri-plugin-single-instance = { version = "2", features = ["deep-link"] }

注意: Windows/Linux 上深链通过 argv 传递给第二个进程,single-instance 插件拦截并转发给主进程。macOS 通过 Apple Events 处理。已有配置已正确处理跨平台。

需新增: 前端路由监听深链事件并导航到对应页面。

// ui/src/renderer/main.tsx 或 Router.tsx 中注册
import { listen } from '@tauri-apps/api/event';

listen('deep-link', (event) => {
  const url = event.payload as string; // "nomifun://approval/detail?id=xxx"
  const path = url.replace('nomifun://', '/');
  navigate(path);
});

支持的深链路径:

深链 目标页面 场景
nomifun://approval/list 审批待办列表 查看待审批
nomifun://approval/detail?id=xxx 审批详情 查看具体审批
nomifun://dashboard 经营看板 查看经营数据

3.4.2 Tauri Opener 插件(打开外部 URL

问题: AppLink 跳转需要从 Tauri 应用中打开外部 URL(https://applink.feishu.cn/...),需使用 Tauri 官方 opener 插件。

需新增依赖:

# apps/desktop/Cargo.toml 新增
tauri-plugin-opener = "2"
// 前端调用
import { openUrl } from '@tauri-apps/plugin-opener';

// 打开飞书审批详情页
await openUrl(
  `https://applink.feishu.cn/client/mini_program/open?appId=cli_9cb844403dbb9108&path=${encodeURIComponent(`pages/detail/index?instanceId=${instanceId}`)}`
);

Capability 配置 (src-tauri/capabilities/default.json):

{
  "permissions": {
    "opener:allow-open-url": {
      "scope": {
        "allow": [{ "url": "https://applink.feishu.cn/**" }]
      }
    }
  }
}

安全约束: opener scope 限制为 applink.feishu.cn 域名,防止任意 URL 跳转。

飞书卡片中也支持 AppLink: 飞书卡片 button 组件的 default_url 字段可直接配置 AppLink URL,用户在飞书聊天中点击卡片按钮即可跳转审批页面,无需经过 NomiFun。参见飞书卡片交互文档

3.5 卡片交互闭环(跳转工作台)

现有能力: Lark Plugin 已处理 card.action.trigger 事件,将按钮回调转为 UnifiedAction(见 handle_card_action() in plugin.rs)。回调解析通过 parse_lark_callback()"category:action:k=v,k=v" 格式拆分,当前仅支持 platform/system/chat 三种 category。

两种卡片按钮模式:

模式 飞书卡片按钮类型 行为 适用场景
URL 直跳 { "tag": "button", "text": "...", "url": "nomifun://..." } 飞书客户端直接打开 URL → OS 层面唤起 NomiFun → Tauri 深链路由 简单跳转(前往审批页、前往看板)
Action 回调 { "tag": "button", "text": "...", "value": { "action": "feishu:approval_preview:code=xxx" } } 触发 card.action.triggerhandle_card_action()parse_lark_callback()route_action() 需要后端处理后再回复的场景(如刷新状态)

审批辅助场景使用 URL 直跳模式(简单可靠,无需后端介入):

{
  "type": "template",
  "data": {
    "template_id": "approval_preview",
    "template_variable": {
      "title": "请假申请预览",
      "applicant": "张三",
      "duration": "7月5日 - 7月7日",
      "type": "事假",
      "actions": [
        { "tag": "button", "text": { "tag": "plain_text", "content": "在飞书中发起" }, "url": "https://applink.feishu.cn/client/mini_program/open?appId=cli_9cb844403dbb9108&path=pc%2Fpages%2Fcreate-form%2Findex%3Fid%3Dleave_v1", "type": "default" }
      ]
    }
  }
}

注意: 卡片中不包含「同意/拒绝」按钮 — 审批操作必须在飞书客户端中由人完成。URL 直跳模式不需要扩展 parse_lark_callback(),飞书客户端原生处理 URL 打开。

可选扩展(Action 回调模式): 若需要在卡片中实现「刷新审批状态」等交互,需扩展 parse_lark_callback() 的 category 白名单,增加 "feishu" 类别,并在 route_action() 中新增对应路由。工作量 1-2 天。

3.6 企业经营看板 (caps_dashboard.rs + 前端页面)

数据来源: 外部数据中台(已完成 ETL 加工的指标数据),通过 REST API 提供。

设计原则:

  • 数据中台负责数据加工(聚合、清洗、建模),NomiFun 只做展示和查询
  • 独立看板页面优先: 用户打开工作台即可看到角色化看板,无需对话即可获取核心指标
  • AI 对话为补充: 用户需深度查询(下钻/对比/自定义时间范围)时,通过自然语言对话与 AI 交互
  • 角色化数据过滤: 不同用户看到不同层级的指标(总部/部门/个人)
  • 权限由后端强制执行,不信任前端传入的 scope 参数

双模式交互:

模式一:独立看板页面(打开即看)
  用户打开工作台 → 看板页面自动加载角色化指标
  → 指标卡片 + 趋势图表 + KPI 进度条
  → 手动刷新 / 切换时间范围

模式二:AI 自然语言对话(深度查询)
  用户在飞书或工作台中提问:
  "本月华东区销售额对比上月怎么样?"
  → AI 调用 nomi_dashboard_trend + nomi_dashboard_breakdown
  → 返回图表卡片 + 文字分析
  → 可继续追问 "按产品线拆分呢?"

MCP 工具定义:

工具名 DangerTier 说明
nomi_dashboard_summary Read 获取当前用户可见的经营概览指标
nomi_dashboard_trend Read 获取指定指标的趋势数据(时间序列)
nomi_dashboard_breakdown Read 按维度下钻指标(部门/产品/区域)
nomi_dashboard_compare Read 多指标对比分析

角色化数据过滤机制:

#[derive(Deserialize, JsonSchema)]
struct DashboardSummaryParams {
    /// 指标分类(如 "sales", "hr", "finance"),可选
    #[serde(default)]
    category: Option<String>,
    /// 时间范围(如 "today", "this_week", "this_month"
    #[serde(default = "default_time_range")]
    time_range: String,
    // 注意:scope/department/user_id 不接受前端传入
    // 由 handler 从 CallerCtx.user_id 解析用户角色后注入
}

角色权限映射:

角色 可见数据范围 示例指标
CEO/高管 全公司 总营收、总利润、人效、增长率
部门负责人 本部门 + 下属部门 部门 KPI、部门人均产出、部门预算执行率
团队主管 本团队 团队任务完成率、团队工时分布
普通员工 个人 个人 KPI、个人任务进度、个人考勤

实现要点:

  1. 用户角色获取链路: CallerCtx.user_id → 查询 user_roles 表 → 确定数据可见范围
    • Channel Surface 链路: 飞书消息 → ActionExecutor::handle_incoming_message()pairing.get_internal_user_id(open_id, "lark")internal_user_id → 传入 ChannelMessageService → AI Agent → CallerCtx.user_id = internal_user_id
    • Desktop Surface 链路: 工作台直接调用 → CallerCtx.user_id = 当前登录用户 ID
    • 角色解析: user_roles 表中 user_id 关联 internal_user_idrole 字段决定数据 scope
    • scope 注入: handler 内部根据 role 计算 scope(如 role=ceoscope=allrole=dept_headscope=dept:{dept_id}),传递给数据中台 API
  2. 数据中台 API 对接: 在 GatewayDeps 中新增 data_platform_client 字段(需在 deps.rs 添加字段 + routes.rs 注入)
  3. 缓存策略: 高频指标在 NomiFun 侧缓存 5 分钟,减少数据中台压力
  4. 前端看板页面: 基于 Arco Design + recharts 构建可视化看板(需先安装 recharts 依赖
  5. 飞书卡片投递: AI 也可通过飞书 Bot 以卡片形式回复经营数据查询

前端看板页面架构:

ui/src/renderer/pages/dashboard/
  ├── DashboardPage.tsx          // 看板主页面(角色化路由)
  ├── components/
  │   ├── MetricCard.tsx         // 指标卡片组件
  │   ├── TrendChart.tsx         // 趋势图表(recharts
  │   ├── BreakdownTable.tsx     // 下钻数据表格
  │   └── KPIProgress.tsx        // KPI 进度条
  ├── hooks/
  │   └── useDashboardData.ts    // 数据获取 hook(调用后端 API
  └── config/
      └── roleWidgets.ts         // 角色 → 看板组件配置映射

数据中台 API 约定:

GET /api/v1/metrics/summary?scope={scope}&category={category}&range={range}
  → { metrics: [{ name, value, unit, change_pct, target, target_pct }] }

GET /api/v1/metrics/trend?metric={metric}&range={range}&granularity={day|week|month}
  → { points: [{ timestamp, value }] }

GET /api/v1/metrics/breakdown?metric={metric}&dimension={department|product|region}
  → { groups: [{ label, value, share_pct }] }

NomiFun 后端在调用时注入 scope(根据用户角色计算),数据中台只返回该 scope 范围内的数据。

飞书卡片 chart 投递技术说明:

现有 build_lark_card() 仅支持 div + lark_md 文本元素(见 sender.rs:66-87)。经营看板需要在飞书卡片中展示图表,需扩展为飞书卡片 JSON 模板的 chart 组件:

// 新增:在 build_lark_card 中支持 chart 类型 element
fn build_lark_chart_element(data: &ChartSpec) -> Value {
    json!({
        "tag": "chart",
        "chart_spec": data.spec,  // 飞书卡片 chart JSON spec
        "mode": "transparent"
    })
}

飞书卡片 chart 组件接受 Vega-Lite 风格的 JSON spec,需将数据中台返回的指标数据转换为飞书 chart spec 格式。工作量 2-3 天(含 spec 转换 + 测试)。

3.7 定时增量同步

现状: 知识库同步通过 HTTP API 手动触发(POST /api/knowledge/:id/sync)。

增强: 在 AppServices 中添加 tokio cron 调度器:

// 每 60 分钟触发一次飞书 Wiki 增量同步
tokio::spawn(async move {
    let mut interval = tokio::time::interval(Duration::from_secs(3600));
    loop {
        interval.tick().await;
        for kb in knowledge_service.list_connector_sources("feishu").await {
            let _ = knowledge_service.sync_connector_source(&kb.id).await;
        }
    }
});

3.8 数据表 Schema 定义

新增 SQLite 表(通过 migration 脚本创建):

feishu_approval_templates — 审批模板映射

CREATE TABLE feishu_approval_templates (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    approval_code TEXT NOT NULL UNIQUE,       -- 飞书审批定义 code
    display_name TEXT NOT NULL,               -- 人类可读名称("请假申请")
    form_schema TEXT NOT NULL,                -- JSON Schema 描述表单字段
    applink_path TEXT NOT NULL,                -- 飞书 AppLink 路径模板
    enabled BOOLEAN DEFAULT 1,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL
);

user_roles — 用户角色映射(经营看板权限)

CREATE TABLE user_roles (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id TEXT NOT NULL,                    -- internal_user_id
    role TEXT NOT NULL,                       -- ceo | dept_head | team_lead | employee
    dept_id TEXT,                             -- 飞书部门 IDdept_head/team_lead 必填)
    scope_override TEXT,                      -- 可选:手动覆盖数据可见范围
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL,
    UNIQUE(user_id)
);

org_cache — 飞书通讯录本地缓存

CREATE TABLE org_cache (
    open_id TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    en_name TEXT,
    department_ids TEXT,                      -- JSON array of dept IDs
    job_title TEXT,
    mobile TEXT,                              -- 加密存储
    email TEXT,                               -- 加密存储
    leader_open_id TEXT,
    raw_json TEXT,                            -- 完整飞书响应(加密)
    cached_at INTEGER NOT NULL,
    expires_at INTEGER NOT NULL               -- cached_at + TTL(15min)
);

audit_logs — 审计日志

CREATE TABLE audit_logs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    created_by TEXT NOT NULL,                 -- user_id
    action TEXT NOT NULL,                     -- 如 "feishu_appr_list", "dashboard_summary"
    target TEXT,                              -- 操作目标(如审批 instance_id
    result TEXT,                              -- success | error:xxx
    surface TEXT,                             -- channel | desktop | remote
    created_at INTEGER NOT NULL
);

Migration 方式: 在 nomifun-db/src/migrations/ 中新增 xxxx_feishu_integration.sql,遵循现有 migration 命名约定。


四、数据流详解

4.1 场景一:AI 辅助审批填表(人在飞书客户端提交)

用户在飞书发送: "帮我发起请假,7月5号到7月7号,事假"

① 飞书 WebSocket → LarkPlugin::handle_message_event()
   → UnifiedIncomingMessage { text: "帮我发起请假...", user: { id: open_id } }

② ChannelOrchestrator → ActionExecutor::handle_incoming_message()
   → pairing.get_internal_user_id(open_id, "lark") → internal_user_id
   → session_mgr.get_or_create_session() → session
   → MessageResult::Dispatched { session_id, conversation_id }

③ ChannelMessageService → AI Agent (nomi)
   → LLM 接收消息 + 工具列表(含 nomi_feishu_*
   → LLM 返回 tool_use: nomi_feishu_appr_templates (获取请假模板结构)

④ 工具执行 (仅查询):
   → McpToolProxy.execute() → stdio bridge → GatewayMcpServer
   → Registry::dispatch_opt() → Capability.handler()
   → 调用飞书审批 API 查询模板定义 → 返回表单结构

⑤ AI Agent 收到模板结构 → LLM 填充表单字段
   → 生成审批预览卡片 JSON + AppLink 跳转链接
   → ChannelMessageService → LarkPlugin::send_card()
   → 飞书渲染预览卡片(含「在飞书中发起」按钮)

⑥ 用户点击「在飞书中发起」
   → AppLink 跳转飞书客户端审批发起页
   → 用户在飞书客户端中确认并提交审批
   → ❌ AI 不参与审批提交操作

⑦ (异步) 审批状态变更
   → 飞书事件订阅 → 或 NomiFun 轮询
   → Webhook 自定义机器人卡片推送到用户/群

4.2 场景二:文档知识问答

用户在飞书发送: "我们的差旅报销标准是什么?"

①-② 同上,消息路由到 AI Agent

③ AI Agent 调用 knowledge_search MCP 工具
   → KnowledgeMcpServer 检索已同步的飞书 Wiki 快照
   → 返回匹配文档片段 + 飞书原文链接 (source_url)

④ AI 整合为自然语言回答
   → "根据《差旅报销管理办法》,国内出差住宿标准为..."
   → 附带飞书文档链接: https://open.feishu.cn/docx/xxx

⑤ LarkPlugin::send_message() → 飞书回复

4.3 场景三:组织架构查询

用户在飞书发送: "产品部有哪些人?"

①-② 同上

③ AI Agent 调用 nomi_feishu_org_dept_tree → 获取部门树
   AI Agent 调用 nomi_feishu_org_search → 按部门搜索员工

④ AI 整合结果:
   → "产品部共 12 人:\n- 张三(产品总监)\n- 李四(产品经理)\n..."
   → 手机号脱敏: 138****1234

⑤ LarkPlugin::send_message() → 飞书回复

4.4 场景四:经营看板查询

用户在飞书发送: "这个月销售情况怎么样?"

①-② 同上,消息路由到 AI Agent

③ AI Agent 调用 nomi_dashboard_summary (category="sales", range="this_month")
   → handler 从 CallerCtx.user_id 解析用户角色 → 确定数据可见范围
   → 调用数据中台 API (注入 scope) → 返回已加工指标

④ AI 整合结果:
   → "本月销售概览:\n- 总销售额:¥1,250,000(环比 +12%\n- 新增客户:85 家(环比 +8%)\n- 客单价:¥14,705(环比 +3.5%)"
   → 附带趋势图卡片(如用户为高管,含部门对比数据)

⑤ LarkPlugin::send_card() → 飞书回复指标卡片

⑥ 用户也可在 NomiFun 桌面端打开「经营看板」页面
   → DashboardPage 根据用户角色渲染差异化看板
   → 指标卡片 + 趋势图表 + 下钻表格

五、飞书应用配置清单

5.1 自建应用创建

  1. 登录 飞书开放平台 → 创建企业自建应用
  2. 获取 App ID + App Secret — 用于 NomiFun connector credential
  3. 配置应用名称、头像、描述

5.2 权限申请

权限范围 权限标识 用途
通讯录 contact:user.base:readonly 搜索/查询员工基本信息
通讯录 contact:user.phone:readonly 查询手机号(需审批)
通讯录 contact:user.email:readonly 查询邮箱(需审批)
通讯录 contact:department.base:readonly 获取部门树
审批 approval:approval:read 查询审批列表/详情/模板(仅读)
审批 approval:approval:write 不申请 — 审批通过 AppLink 跳转飞书客户端由人执行
文档 wiki:wiki:readonly 读取 Wiki 空间节点
文档 docx:document:readonly 读取文档内容(blocks
消息 im:message 接收消息
消息 im:message:send_as_bot 以机器人身份发送消息
消息 im:chat:readonly 获取群信息

5.3 事件订阅

  • 模式: WebSocketNomiFun 已支持,无需公网回调地址)
  • 订阅事件:
    • im.message.receive_v1 — 接收消息
    • card.action.trigger — 卡片按钮回调
    • application.bot.menu_v6 — 机器人菜单点击

5.4 机器人配置

  • 启用机器人能力
  • 配置指令菜单(可选):查审批查文档找人看板
  • 配置欢迎语

5.5 审批应用配置

  • 在飞书管理后台 → 审批管理中确认审批模板
  • 获取每个模板的 approval_code
  • 在 NomiFun 中配置 feishu_approval_templates
  • 不申请审批写入权限 — 审批操作通过 AppLink 跳转飞书客户端由人完成

5.6 数据中台对接配置

  • 确认数据中台 API 地址、认证方式(API Key / OAuth
  • 在 NomiFun 中配置 data_platform 连接信息(加密存储)
  • 定义角色 → 数据 scope 映射规则(user_roles 表)
  • 确认数据中台已加工好所需指标(NomiFun 不做 ETL

六、安全与合规评估

6.1 密钥管理

密钥 存储方式 风险评估
app_id / app_secret NomiFun connector credential 加密存储 不进 Git,仅 .env.example
tenant_access_token 内存缓存,30min 过期 不持久化
Webhook 签名密钥 webhook 配置加密存储 HMAC-SHA256 签名验证
数据中台 API Key NomiFun 加密存储 不进 Git,仅 .env.example

6.2 权限边界

  • 飞书 App 可见范围 = NomiFun 可访问的数据边界
  • 后端独立校验: ActionExecutorpairing.get_internal_user_id() 强制做 open_id → internal_user_id 映射,不信任请求体中的 user_id
  • Surface 权限矩阵: Destructive/Sensitive 操作在 Channel Surface 硬拒绝
  • 审批不封装写入工具: 审批创建/同意/拒绝不作为 MCP 工具,AI 无法越权执行
  • 看板角色过滤: scope 由后端从 CallerCtx.user_id 解析注入,不信任前端传入

6.3 PII 脱敏

  • 手机号: 138****1234
  • 邮箱: z***@company.com
  • 身份证: 110***********1234
  • 脱敏在 MCP 工具 handler 层执行,确保不进入 LLM context

6.4 审计日志

  • 所有审批查询操作记录到 audit_logs 表(审批执行在飞书侧已有审计)
  • 看板数据查询记录到 audit_logs
  • 字段: created_by / action / target / result / created_at
  • 保留 ≥ 6 个月

6.5 注入防御

  • AI 辅助填表预览仅生成 AppLink 链接,不直接提交审批 → 飞书客户端校验表单有效性
  • 用户输入与系统 prompt 分离 role,防 prompt injection
  • LLM 输出的 tool_use 参数经 Capability::new() 的 typed deserialization 校验
  • 看板数据中台 API Key 不暴露给 LLM context

七、实现路线图

Phase 0: 即用即有(0 天)

能力 说明
飞书 Bot 消息收发 配置自建应用 WebSocket 即可
飞书 Wiki 文档同步 配置 connector credential + space_id
AI 知识问答 文档同步后自动可用
Webhook 群通知 配置飞书自定义机器人 webhook URL

Phase 1a: MCP 查询工具 + 经营看板页面 + 深链基础设施(11-18 天)

任务 工作量 依赖
提取 FeishuConnector 公共能力(token/限流/authed_get 1 天 -
caps_feishu_org.rs — 3 个组织架构工具 3-5 天 公共能力
caps_feishu_approval.rs — 3 个审批查询工具(仅读) 3-4 天 公共能力
caps_dashboard.rs — 4 个经营看板工具 5-8 天 数据中台 API
安装 recharts 依赖 + 看板前端页面 (DashboardPage + 组件) 6-10 天 看板工具
飞书卡片 chart 组件投递(扩展 build_lark_card 2-3 天 看板工具
数据表 migration + Tauri opener 插件 1 天 -
集成测试 2-3 天 全部

Phase 1a 交付价值:

  • 经营看板页面: 用户打开工作台即可看到角色化看板(指标卡片 + 趋势图 + KPI 进度)
  • AI 聊天查询: 飞书聊天中可查组织架构、审批待办/详情、经营指标(含卡片 chart 可视化)
  • 深度对话分析: 用户可通过自然语言追问下钻/对比,AI 调用 dashboard 工具返回图表 + 分析
  • 深链 + Opener 基础设施: Tauri 深链已就绪 + opener 插件就绪,为 Phase 1b 审批跳转铺路

Phase 1b: 审批工作台 UI5-7 天)

任务 工作量 依赖
审批列表/详情 UI(原生 React + Arco 3-4 天 Phase 1a 查询工具
AppLink 跳转按钮 + Tauri opener 集成 1 天 Phase 1a opener
Tauri 深链前端路由监听 0.5 天 -
审批侧边栏集成(ChatSlider extraTabs 0.5 天 审批列表 UI
飞书审批模板管理表 0.5 天 审批工具
集成测试 0.5-1 天 全部

Phase 1b 交付价值: 工作台可视化审批列表/详情,用户点击「在飞书中处理」跳转飞书客户端完成审批操作。

Phase 2: 交互增强(2-4 天)

任务 工作量 依赖
卡片交互路由扩展 (action.rs) 1-2 天 Phase 1a
审批预览卡片模板 1 天 卡片路由
审批状态变更推送 1 天 Webhook 已有

Phase 3: 自动化与精细化(4-7 天)

任务 工作量 依赖
定时增量同步调度 1-2 天 Phase 0
权限感知搜索(按用户过滤文档) 3-5 天 Phase 1a 组织架构

总工作量

阶段 天数 累计 交付物
Phase 0 0 0 飞书 Bot + Wiki 同步 + Webhook
Phase 1a 11-18 11-18 MCP 查询工具 + 经营看板页面 + 深链/opener 基础设施 + AI 聊天查询
Phase 1b 5-7 16-25 审批工作台 UI(列表/详情 + AppLink 跳转 + 深链)
Phase 2 2-4 18-29 卡片交互增强
Phase 3 4-7 22-36 自动化调度 + 权限搜索

对比 v3.0: 首个可用版本 11-18 天(含看板页面 + 深链);总工作量 22-36 天。v3.4 通过 AppLink 跳转模式消除 OAuth/动态表单/后端写代理,比 v3.3 的 28-46 天减少 6-10 天。


八、风险评估与缓解

8.1 技术风险

风险 级别 缓解措施
飞书 API 限流导致同步失败 Connector 已实现 4 QPS 限流 + 429 重试;通讯录加本地缓存
LLM 误填审批表单 表单在飞书客户端中填写 + 飞书原生校验;AI 仅生成预填数据,人工确认
飞书 WebSocket 断连 Plugin 已有自动重连逻辑
文档类型限制(仅 docx Phase 1 不影响;后续可扩展 Sheet/Mindnote 支持
数据中台 API 不可用 NomiFun 侧 5min 缓存 + 降级提示「数据暂不可用」
数据中台指标口径变更 版本化 API 约定 + 季度对齐检查
飞书 JS SDK 兼容性 已消除 — v3.4 不使用 H5 JS SDKAppLink 跳转飞书原生审批 UI
飞书 OAuth redirect_uri 已消除 — v3.4 不需要 OAuth,AppLink 跳转利用飞书客户端登录态
动态表单字段类型覆盖不全 已消除 — v3.4 不渲染表单,飞书原生表单引擎处理
user_access_token 过期 已消除 — v3.4 不使用 user_access_token
Tauri 深链未注册 项目已配置 tauri-plugin-deep-linknomifun scheme 已注册
AppLink 跳转失败(未安装飞书) AppLink 网页会提示下载飞书;NomiFun 可检测并提示用户
tauri-plugin-opener 权限配置 scope 限制为 applink.feishu.cn 域名,Tauri 官方插件

8.2 业务风险

风险 级别 缓解措施
审批权限过大(AI 可代替人审批) 已消除 — 审批不封装为 MCP 工具,AI 无法执行审批操作
组织架构数据泄露 飞书 App 可见范围控制;PII 脱敏;后端独立校验
用户绑定错误(open_id 映射到错误账号) pairing 服务强制验证;首次使用需配对确认

8.3 错误降级策略

场景 级行为 用户感知
数据中台 API 不可用 返回缓存数据(如有)+ 提示「数据可能非最新」 看板显示缓存指标 + 警告标识
数据中台 API 超时 5s 超时 → 返回缓存或空状态 看板显示「数据加载中」骨架屏
飞书审批 API 不可用 MCP 工具返回错误 JSON → AI 告知用户 AI 回复「审批服务暂时不可用」
飞书通讯录 API 限流 返回 org_cache 缓存数据(TTL 15min AI 回复缓存数据(可能略旧)
飞书知识库同步失败 保留上次成功快照 AI 仍可检索旧快照
AppLink 跳转失败 检测飞书是否安装;未安装时提示下载链接 用户可手动打开飞书审批中心
Tauri 深链未注册 卡片 URL 改为 HTTPS 网页版降级链接 用户在浏览器中查看审批
LLM 工具调用超时 30s 超时 → AI 回复「查询超时,请稍后重试」 用户可重新提问

8.4 体验风险

风险 级别 缓解措施
AI 回复延迟(多工具调用链路长) streaming dispatch 已支持;卡片预览减少往返
看板数据刷新延迟 5min 缓存 + 手动刷新按钮;飞书侧 AI 查询实时获取
飞书卡片兼容性 使用飞书标准 template API;测试不同端(PC/iOS/Android
群聊 @bot 误触发 require_mention 配置项已有
深链跳转后页面状态丢失 深链参数写入 URL query,页面加载时从 query 恢复预填数据
AppLink 跳转后用户需手动返回 NomiFun 审批完成后 Webhook 推送状态变更通知;用户可点击通知返回

九、测试策略

9.1 后端单元测试

模块 测试方式 覆盖点
caps_feishu_org.rs wiremock 模拟飞书 API 搜索/部门树/用户详情 + 限流 + 401 刷新 + PII 脱敏
caps_feishu_approval.rs wiremock 模拟飞书审批 API 列表/详情/模板查询 + 空结果 + 分页
caps_dashboard.rs wiremock 模拟数据中台 API 概览/趋势/下钻/对比 + 角色过滤 + 缓存命中
通讯录缓存 SQLite in-memory TTL 过期 + 缓存命中 + 缓存未命中
角色权限映射 SQLite in-memory 各角色 scope 计算 + scope_override

参考: connector_feishu.rs 已有 8 个 wiremock 测试用例,新模块遵循相同模式。

9.2 前端组件测试

组件 测试方式 覆盖点
ApprovalListPage React Testing Library 列表渲染 + 空状态 + 加载状态
ApprovalDetailPage React Testing Library 详情展示 + 时间线 + 操作按钮
DashboardPage React Testing Library 角色化渲染 + 指标卡片 + 图表
OpenInFeishuButton Mock opener plugin AppLink URL 构造 + 跳转触发
深链路由 Mock Tauri event URL 解析 + 路由导航 + 参数传递

9.3 集成测试

场景 测试方式 验证点
飞书消息 → AI → 工具调用 → 回复 端到端 mock 完整链路无断裂
审批辅助填表 → 卡片 → 深链跳转 手动 + Playwright 预填数据正确传递到工作台
看板角色化数据 多用户 mock 不同角色看到不同数据范围
AppLink 跳转流程 手动 + Playwright AppLink URL 正确性 + 飞书客户端唤起 + 审批页面打开
审批状态变更推送 Mock webhook 审批同意/拒绝后 Webhook 通知正确送达

9.4 回归测试

  • Registry 自测: 新增工具注册后,all_caps_modules_are_mod_declared_and_registered CI 测试自动验证(见 registry/mod.rs 注释)
  • 权限矩阵回归: 新增 Read 级工具在 Channel Surface 自动放行,无需额外配置
  • 工具名长度: Registry 自测强制工具名 ≤ 42 字符

十、与企微(WeCom)的未来扩展

NomiFun 的架构设计天然支持多平台扩展:

  1. Channel Plugin trait: crates/backend/nomifun-channel/src/plugin.rs 定义了 ChannelPlugin trait,新增企微只需实现该 trait
  2. Connector trait: KnowledgeConnector trait 可新增 WeComConnector 实现企微文档同步
  3. MCP 工具域: 飞书工具命名为 nomi_feishu_*,企微工具命名为 nomi_wecom_*,共享 domain 标签或独立
  4. Webhook: sender.rs 已支持多平台格式,新增企微格式即可
  5. 权限矩阵: 企微消息同样走 Surface::Channel,复用现有安全策略

预估额外工作量: 10-15 天(主要是企微 API 对接 + Channel Plugin 实现)


十一、结论

可行性评估: 高度可行

NomiFun 现有架构与飞书集成高度契合:

基础设施 就绪度 说明
飞书消息通道 100% WebSocket、消息收发、卡片交互全部已实现
飞书知识库同步 100% Connector 完整实现,含增量同步、限流、测试
MCP 工具总线 100% 132+ 工具已注册,新增工具只需 3 步
AI Agent 工具调用 100% 完整链路从消息到工具执行到回复已打通
Webhook 通知 100% 飞书卡片 + HMAC 签名已实现
权限与安全 100% Surface × DangerTier 矩阵 + 配对授权 + PII 脱敏
前端基础设施 75% Arco Design 已有;recharts 需新增依赖;看板/审批页面需新建
数据中台对接 0% 需新建 caps_dashboard 域 + 数据中台 API client

核心结论

  • Phase 0 零代码: 配置飞书自建应用即可启用消息通道和文档同步
  • Phase 1a 首个可用版本 ~11-18 天: MCP 查询工具 + 经营看板页面 + 深链/opener 基础设施上线,用户打开工作台即可看角色化看板,AI 聊天中可深度查询
  • Phase 1b 审批工作台 UI ~5-7 天: 审批列表/详情 + AppLink 跳转飞书客户端 + Tauri 深链
  • 总工作量 ~22-36 天: 含交互增强、自动化调度、Tauri 深链、opener 插件
  • 审批安全: AI 仅查询/辅助填表,审批操作全部由人在飞书客户端中完成(AppLink 跳转 + 飞书原生表单 + 飞书登录态)
  • AppLink 跳转模式: v3.4 消除了 v3.3 的 OAuth/动态表单/后端写代理三大复杂度,工作量减少 6-10 天,且保留增量升级路径
  • 看板角色化: 后端强制角色过滤,不同用户看到不同层级指标
  • 安全合规: 权限矩阵、审计日志、PII 脱敏全覆盖
  • 可扩展: 架构天然支持企微等未来平台扩展
  • 错误降级: 每个外部依赖均有降级策略,确保单点故障不影响整体可用性
  • 测试覆盖: 后端 wiremock + 前端 RTL + 端到端集成测试,遵循现有测试模式