# 架构审查报告（2026-06-15）

> 范围：Rust workspace（8 crate + src-tauri 汇聚层，14586 行）+ 前端（Vue3+Pinia，11830 行），共约 26k 行。
> 方法：2 个 general-purpose 子代理并行审「Rust crate 架构」「前端架构」，主代理直读 df-core/df-execute/coordinator/conditions 核实空壳与抽象层，并对 3 个 🔴 删代码/可见断言做 grep 复验（全部坐实）。
> 去重：与 [全栈代码审查报告-2026-06-14.md](全栈代码审查报告-2026-06-14.md)（bug/性能 FR-*）、[架构与缺陷复核报告-2026-06-14.md](架构与缺陷复核报告-2026-06-14.md)（复核+回归审计）、[aichat审查报告-2026-06-14.md](../02-架构设计/构想审查/aichat审查报告-2026-06-14.md)（AR 系列）互补——**本报告只记架构层面**（模块边界/依赖方向/抽象层次/扩展性/状态管理/技术债），不重复 bug、性能、aichat 专项项。
> 性质：**dry — 仅审查 + 文档，不改代码**。

---

## §1 架构总览

### 1.1 Crate 地图（Rust）

| Crate | 职责 | 内部依赖 | 行数 |
|-------|------|---------|------|
| **df-core** | 纯类型定义（ID 别名/状态枚举/new_id）+ error + events | 无（根） | 429 |
| **df-storage** | SQLite 持久化（11 个 Repo + models + migrations） | df-core | 2522 |
| **df-workflow** | 工作流引擎（DAG/Node trait/Executor/Registry/StateMachine/EventBus/Conditions） | df-core | 1120 |
| **df-ai** | AI 编排（LlmProvider trait + OpenAI/Anthropic compat + 工具注册 + 上下文 + 流式） | df-core | 2588 |
| **df-nodes** | 3 个内置节点（AiNode/ScriptNode/HumanNode） | df-core + df-workflow + df-ai + df-execute | 773 |
| **df-execute** | 仅一个 `shell::execute` 函数（带 TODO） | df-core | 76 |
| **df-ideas** | 想法池领域（capture/scoring/adversarial 启发式/promotion 占位） | df-core | 759 |
| **df-project** | 项目领域（create_from_idea / scan 技术栈探测） | df-core | 486 |
| **src-tauri** | 汇聚层：47 个 IPC 命令 + AppState + 跨 crate 业务编排 | 全部 8 crate | 5711 |

**依赖图（无环，星型收敛）**：
```
        df-core (零依赖根)
       /  /  |  \  \  \
   storage workflow ai ideas project execute
              |   |          |
              └───┴── nodes (唯一多依赖者)
                        |
                     src-tauri (依赖全部 8 crate)
```
除 df-nodes 依赖 df-workflow+df-ai 外，**6 个 crate 间零横向依赖**——业务域 crate（ideas/project）不依赖持久化层（storage），靠 src-tauri 在 IPC 层组合。

### 1.2 前端分层地图

| 层 | 关键文件 | 职责 | 备注 |
|----|---------|------|------|
| stores | project(337) / ai(84) / knowledge(157) / appSettings(139) / settings(99) | 领域状态 | project 是上帝 store；settings 死代码 |
| composables/ai | 6 文件（events/stream/send/conversations/window/panel） | AI 业务逻辑 | 为拆而拆，循环依赖 |
| views | 9 个（4875 行） | 页面 | Ideas 929 / Settings 1032 偏重 |
| components | AiChat(1359) / ToolCard(760) 等 | UI 组件 | AiChat 巨型 |
| api | 8 文件（736 行） | Tauri invoke 封装 | 分层清晰 |

---

## §2 架构级问题清单

### 🔴 结构风险（6）

#### ① [df-execute] 空壳 crate + src-tauri 死依赖 — 应合并删除
**现状**：`crates/df-execute/src/lib.rs:7` 仅 `pub mod shell;`；`shell.rs` 全文 73 行只 1 个 `execute` 函数且带 `TODO: 完整实现`（:33）。全仓库唯一调用方是 `df-nodes/src/script_node.rs:34,42`。`src-tauri/Cargo.toml:32` 声明 `df-execute` 依赖，但 grep 确认 `src-tauri/src/` **零处引用 `df_execute`**（已复验）。
**架构影响**：一个 76 行/2 文件、仅暴露 1 函数的 crate，是过度拆分典型。其存在理由（"执行运行时"，原含 docker/git_ops/ssh）重构删除后已不成立。src-tauri 那条依赖是残留死代码。
**建议**：合并 df-execute 进 df-nodes（作 `script_node` 内部模块或 `df-nodes::shell`），删该 crate + `src-tauri/Cargo.toml:32` 死依赖。净减 1 crate + 1 死依赖。

#### ② [stores/settings.ts] mock 上帝 store 死代码 — 零消费者
**现状**：`stores/settings.ts:32-75` 持硬编码 mock 数据（Anthropic/Zhipu/DeepSeek provider、5 连接、theme/dataDir），全写死展示字符串。grep 确认仅 `stores/index.ts:6` 导出，**全 src 零组件 import `useSettingsStore`**（已复验）。真实 provider CRUD 走 `api/ai.ts` + Settings.vue 本地 ref，真实偏好走 appSettings。
**架构影响**：双轨幻觉——同名 `settings` 一真（appSettings/SQLite）一假（settings.ts/mock），后者 `AIProvider`/`Connection` interface 还被 re-export，新人易误用。与「做减法」画像直接冲突。
**建议**：删 `stores/settings.ts` + `stores/index.ts:6-7` 导出；interface 若有外部依赖迁 `api/types.ts`。零风险减法。

#### ③ [stores/project.ts] 上帝 store（四领域强耦合 + 越层 invoke）
**现状**：`project.ts` 同时管 projects/tasks/ideas/workflowExecutions/liveEvents/pendingApproval 六类 state（:9-25），方法覆盖四领域 CRUD + 事件监听 + 审批。`project.ts:252` `invoke('approve_human_approval')`、`:271` `invoke('cancel_workflow_node')` **直接调 invoke 绕过 api 层**——全项目仅此一处 store 越层（其余 50+ invoke 全在 `api/*.ts`）。
**架构影响**：违反单一职责；workflow 审批逻辑寄生 project store；分层不彻底。
**建议**：拆 project/task/idea/workflow 四 store（至少 workflow+审批独立）；`approve_human_approval`/`cancel_workflow_node` 沉 `api/workflow.ts`。

#### ④ [composables/ai/] 6 文件为拆而拆 — events↔stream 循环依赖
**现状**：6 个 composable 全部 `import { state } from stores/ai`（共享单例），且互相模块级 import 形成环：`useAiEvents.ts:18` → useAiStream(reset)；`useAiStream.ts:12` → useAiEvents(nextMsgId) ← **双向**；`useAiSend`→useAiStream+useAiEvents；`useAiConversations`→useAiEvents+useAiPanel；`useAiWindow`→其余三者。`useAiStore()` 只是 `...useAiXxx()` 展开，每个 composable 恰被一处展开、零外部复用。
**架构影响**：拆分未降耦合，反把一个内聚状态机（流式事件→看门狗→队列→对话）打散到 6 文件，靠 ES module 循环 import 维持。events↔stream 双向依赖靠函数提升侥幸可运行，属脆弱结构。
**建议**：要么承认是单 store 内聚逻辑、合回 `stores/ai.ts`（最简）；要么把 `nextMsgId`/`state` 等共享提独立 `aiShared.ts` 破环。

#### ⑤ [App.vue:273] `/decisions` 路由死链 — 用户可见坏链
**现状**：`App.vue:273` secondaryNav 含 `{ path: '/decisions', label: 'nav.decisions' }`，但 `router/index.ts` 无此路由（已复验，仅 i18n 文案存在）。点击落空白/重定向。
**架构影响**：导航与路由不同步，用户可感。
**建议**：补路由+视图，或从 secondaryNav 删该项（务实减法）。

#### ⑥ [前端] 模块级全局态散落 + 多窗口 localStorage 手搓同步
**现状**：跨组件状态大量用模块级 `let`/`const` 而非 store——`useAiEvents.ts:27-32` 四个、`useAiStream.ts:18` watchdog、`useAiWindow.ts:17-18`、`useAiConversations.ts:44` switchId、`stores/project.ts:27,329`。多窗口（主窗口+ai-detached）各独立 JS realm，模块级单例**不跨窗口共享**；`useAiWindow.ts:30-31` 用 `localStorage.setItem('df-ai-gen'/'df-ai-text')` 手动快照，分离窗口 `resumeInDetached`(:82-95) 读回——手搓跨窗口 IPC，仅覆盖 currentText 两字段。
**架构影响**：模块级 state 单窗口内是隐式全局，调试难追踪；「双窗口同时操作同一对话」竞态靠 localStorage 单字段兜不住。
**建议**：跨窗口状态显式走 Tauri event（emit/listen）而非 localStorage 快照；模块级私有态集中文档化。

### 🟡 改进（6）

#### ⑦ [df-core] 名不副实——类型库而非核心
`lib.rs:5` 自述"核心类型定义"，但 `types.rs` 全是 `pub type XId = String` 别名 + 状态枚举 + `new_id()`，**无 trait/无抽象/无行为契约**。真正核心 trait（`Node` 在 df-workflow、`LlmProvider` 在 df-ai）各自下沉到功能 crate。命名误导读者对其角色预期。**建议**：改名 `df-types`，或注释明确"只放跨 crate 共享数据类型，不放 trait"。低优先。

#### ⑧ [src-tauri] IPC 层成事实业务编排层（5711 行）
crate 故意解耦（ideas 不依赖 project/storage），代价是「两 crate 怎么协作」无处安放，全部上浮 src-tauri。典型 `commands/idea.rs:96-161` `promote_idea`：取 IdeaRecord → 调 df_project 构造 Project → 插 df_storage → 补偿删除 → 回写 ideas，其中 `record_to_idea`(:252)、分数 `*10` 缩放(:224)、JSON 组装(:208) 全在 IPC 文件。`df-ideas/promotion.rs:82` 的 `do_promote` 反而是空壳——领域逻辑被分置两处，领域 crate 残缺。src-tauri(5711) > 最大 crate(df-ai 2588)，IPC 不是薄转发而是应用服务层。**建议**：中期引入 `df-app` 或 src-tauri 内 `services/` 收编跨 crate 编排，让 IPC 回归薄转发；至少把 `record_to_idea` 这类纯映射下沉回 df-ideas。技术债，不紧急。

#### ⑨ [src-tauri/commands/ai] AI agent loop 在 IPC 层而非 df-ai
`commands/ai/` 11 文件 3438 行，含 `agentic.rs`(292) ReAct 主循环、`audit.rs`(342) 工具审计、`knowledge_inject.rs`(557) 提炼。df-ai 提供 trait + provider 实现，但「怎么编排多轮工具调用」这层智能在 src-tauri，使 df-ai 退化为「LLM 调用 SDK」。与 aichat 审查「单链 ReAct、coordinator 空壳」一致——智能层无处安放暂栖 IPC。**建议**：观察项，B 路线（多 agent 协作）立项时一并从 IPC 抽出，现不宜妄动。

#### ⑩ [views] 3 个 view 绕 store 调 api
`Projects.vue:160,163,187`（scanStack/checkBinding/scanWithAi）+ `ProjectDetail.vue:211` 混用 store 与 api；`Settings.vue:374,387` 完全不走 store（provider CRUD 直接 aiApi + 本地 ref），自带 toast(:390) 与 App.vue 全局 toast 重复。分层不一致——同性质「读后端数据」有的进 store 有的留 view 本地。**建议**：scan/checkBinding 预览型只读可接受；Settings provider 列表应进 store（与 `stores/ai.ts:39` providers 合一，避免双份真源）；toast 二选一。

#### ⑪ [stores/index.ts] barrel 漏导 useAiStore
`stores/index.ts` 导出 project/knowledge/settings/appSettings，**漏 `useAiStore`**（`stores/ai.ts:73`）。故 App.vue/AiChat.vue/AiDetached.vue 全部直连 `stores/ai` 文件绕过 barrel。barrel 形同虚设，ai store 成「特殊公民」。**建议**：补 `export { useAiStore } from './ai'`。

#### ⑫ [api/types.ts] 前后端类型契约手写 + `as any` 绕过
`api/types.ts:1` 注释"与 Rust Record 严格对齐"但纯手写无代码生成。漂移风险点：`stores/project.ts:234` `payload.event as unknown as HumanApprovalRequest`（字段存在性无校验）；`:73,145,182` `(state.xxx[idx] as any)[field]=value`（field 是 string 无约束）；`useAiConversations.ts:71` 历史消息全程 `(m:any)`、`:81` JSON.parse 无 try-catch；Settings/ToolCard 多处 `as any`。契约脆弱集中在「动态字段更新」和「事件 payload 强转」。**建议**：动态 field 改 keyof 约束或具名方法；payload 强转改类型守卫；长期考虑 ts-rs 代码生成。

### ⚪ 观察（4）

**⑬ [df-ai/coordinator.rs:3 等] 空壳是 B 路线有意占位** — `coordinator.rs:3` 注释 `⚠ B 路线占位...勿删`；`df-workflow/conditions.rs:4` `TODO: 实现完整条件表达式`（当前只识 true/false 字面量，保守拒绝=安全）；`df-ai/router.rs:42` ModelRouter 全返 default_model（no-op）；`df-ideas/promotion.rs:67` SemiAuto TODO。coordinator 有明确归属保留；conditions/router 若长期无调用方依赖其"未来能力"，可删减负（YAGNI）。决策性。

**⑭ [AiSession] 单例 + generating bool 锁死多会话并发** — `state.rs:164` `ai_session: Arc<Mutex<AiSession>>`（全局唯一），`commands.rs:45,48` `generating` bool 充当全局对话互斥锁，`state.rs:93-96` 注释自承认"per_conv 是应用级单一信号量非 map，未来多对话并发需改 HashMap"。同一时刻全局只能有一个 AI 对话生成。是有意识的设计取舍，符合单链 ReAct 现状，但是异步审批/多会话（见 memory devflow-async-approval-concept）的结构前置障碍。B 路线范畴，现不阻塞。

**⑮ [AppState] God Struct** — `state.rs:135-185` 含 15 个 Repo + event_bus + registry + ai_tools + ai_session + knowledge_config + llm_concurrency + workflow_state_registry。所有 IPC 共享巨型 State，无边界隔离。桌面应用规模可接受，若 IPC 做 service 化（⑧）State 可随之分组。

**⑯ [前端] IPC 命名风格不统一** — 命令名 snake_case（`list_projects`）/`ai_`前缀（`ai_chat_send`）混存；参数 camelCase（`convId`）vs snake（`projectId`）混。新增 IPC 需改 api+store+view 约 3 处，散弹度可接受。**建议**：命令名统一 snake_case，参数统一 camelCase（Tauri 自动转）。

---

## §3 亮点

- **扩展点单点注册，抽象得当**：新增工作流节点改 2 处（df-nodes 加 impl Node + `state.rs:225 build_registry` 注册一行）；新增 AI 工具改 1 处（`tool_registry.rs` register）；新增 provider 改 1 处（`df-ai/lib.rs:21 build_provider` match）。Registry/工厂用最朴素 HashMap，没搞插件动态加载那套过度抽象。**架构最健康的一面**。
- **依赖图无环、星型收敛**：crate 间零横向耦合，编译/测试隔离好，6 crate 不互相牵连。
- **空壳占位有显式标注**：coordinator 的 B 路线注释、conditions 的保守拒绝设计，非失控，是有意识的路线占位。
- **前端减法实践**：`useConfirm`（抽 4 视图重复）、`constants/project`（统一状态映射）、`utils/time`（根治 Invalid Date）——好的减法。
- **i18n/路由/api 分层清晰**：i18n 按模块分文件 zh/en 对称，路由全懒加载带 meta，api 层 8 文件按领域分 + barrel 统一导出（除 ③ project store 越层、⑪ ai store 漏导两处瑕疵）。
- **工程素养细节**：LlmConcurrency 双层 Semaphore、promote_idea 补偿事务删除、FR-S7/S8 安全防护——显工程功底。

---

## §4 总评

**架构成熟度：中等偏清晰（Rust 7/10，前端 6/10）**。

**核心张力（1 个真问题 + 几个取舍）**：
- **真问题**：df-execute 空壳化 + src-tauri 死依赖（①），应做减法合并。这是唯一违背「做减法」画像的硬伤。
- **核心张力**：crate 刻意解耦 → 跨 crate 编排全部上浮 src-tauri → IPC 层 5711 行成事实业务层（⑧⑨）。这是「高内聚低耦合」的代价，当前规模可忍，是中期技术债。
- **前端回潮**：AI 模块过度拆分（④）、project 上帝 store（③）、settings 死代码（②）三处结构性债。

**务实画像契合度**：整体偏「做减法、反过度抽象」——没为插件化搞动态加载、没给 df-core 塞虚 trait、Registry 用朴素 HashMap。违背处集中在 df-execute 存在（应删）和 src-tauri 膨胀（编排无处去）+ 前端 AI 模块拆分。

**行动建议（按 ROI）**：
| 优先级 | 项 | 动作 | 成本 |
|--------|-----|------|------|
| 立即 | ② | 删 stores/settings.ts 死代码 | 零风险 |
| 立即 | ⑤ | /decisions 死链（补路由 or 删 nav） | 零风险 |
| 短期 | ① | df-execute 合并进 df-nodes + 删死依赖 | 低（1 crate+1 依赖） |
| 短期 | ⑪ | stores/index.ts 补 useAiStore 导出 | 极低 |
| 中期 | ③ | project.ts 拆分 + 审批沉 api 层 | 中 |
| 中期 | ④ | ai composables 合回 or 破环 | 中 |
| B 路线 | ⑧⑨⑭ | IPC 编排层抽取 / agent loop 下沉 / AiSession 多会话 | 大（随 B 路线） |
