refactor: 全栈架构重构与质量硬化——API 错误统一、工具域重组、安全加固、前端组件化

后端核心变更:
  - API 层: 新增 AppError 枚举统一错误类型,替代散落的 (StatusCode, String)
  - Agent 工具域: 重组为 astro/system/ 和 astro/research/ 两级域,新增 ProcessPaperTool 流水线工具
  - 安全: 新增 SSRF 双层防护 (同步字符串级 + 异步 DNS 解析级),覆盖 IPv4/IPv6 私网段
  - 弱密码检测: 扩展弱密码列表并增加最小长度检查
  - LLM 客户端: 新增 ChatCompleter/Embedder trait,支持依赖注入与批量向量化 embed_batch
  - 批量处理: AssetBatch 从串行改为 Semaphore 并发池 (BATCH_CONCURRENCY=3)
  - 分块器: 重写为三阶段结构化管线 (章节解析→短节合并→带标题路径子块)
  - RAG: embedding 计算移出事务,RetrievalResult 新增 headings/section_index 字段
  - 检索: ADS/arXiv 并行检索 (tokio::join!),去重改用 HashSet,本地库回填批量 IN 查询
  - 天体查询: Sesame API 升级到 v4,新增视差误差/自行/视向速度/多波段测光字段
  - 迁移: 14 个增量文件合并为单一 init.sql,支持 sqlx::migrate! 内存库集成测试
  - 测试: circuit_breaker/hooks/task_board/session/memory/streaming_executor 新增修正 15+ 测试

  前端架构重构:
  - 目录重组: features/ → pages/ + components/ + hooks/ 三层分离
  - App.tsx 从 1181 行压缩至 ~174 行 (逻辑抽入 9 个自定义 Hook)
  - Agent 面板拆分为 AgentSessionSidebar/AgentMessageList/AgentInputArea 子组件
  - 新增 GlobalDialog/PaperDetailModal/UncachedPaperModal 通用对话框组件
  - 工具函数抽取: celestial.ts (天体坐标格式), paper.tsx (文献信息渲染)
This commit is contained in:
fmq
2026-06-25 23:45:37 +08:00
parent b11b8ad015
commit 5db4cc5998
131 changed files with 13934 additions and 7887 deletions
+11 -7
View File
@@ -43,14 +43,18 @@ AstroResearch 是一个集成了天文学文献检索、多通道下载(含防
### 3.5 前端核心组件 (`dashboard/src/`)
| 组件文件 | 职责 |
| 目录/组件文件 | 职责 |
|:---|:---|
| **[App.tsx](../dashboard/src/App.tsx)** | 全局状态管理:Tab 持久化、手动上传处理、无资源标记、活跃文献追踪、详情弹窗(含错误诊断和上传区)。 |
| **[components/CustomSelect.tsx](../dashboard/src/components/CustomSelect.tsx)** | 可复用下拉选择组件:统一视觉风格、点击外部关闭、选中高亮。 |
| **[components/CitationGalaxyCanvas.tsx](../dashboard/src/components/CitationGalaxyCanvas.tsx)** | 基于 HTML5 Canvas 的自研力导向引文星系图谱引擎:节点排斥力、中心引力、拖拽阻尼、双击多层级衍生。 |
| **[features/library/LibraryPanel.tsx](../dashboard/src/features/library/LibraryPanel.tsx)** | 馆藏管理面板:同步反馈、下载失败/无资源状态筛选、文献类型筛选(13 种)、状态优先排序。 |
| **[features/search/SearchPanel.tsx](../dashboard/src/features/search/SearchPanel.tsx)** | 跨源检索面板:高级组合条件、排序分页、下载失败状态提示、文献类型徽章(16 种)。 |
| **[features/sync/SyncPanel.tsx](../dashboard/src/features/sync/SyncPanel.tsx)** | 批量同步控制台:乐观 UI 更新、容器内日志自动滚动。 |
| **[App.tsx](../dashboard/src/App.tsx)** | 全局骨架与胶水层:鉴权外壳、Tab 持久化、挂载全局弹窗,调度各页面跨组件跳转逻辑。 |
| **[pages/SearchPanel.tsx](../dashboard/src/pages/SearchPanel.tsx)** | 统一跨源检索页面:支持高级检索构造、分页排序以及下载错误状态提示与文献类型徽章显示。 |
| **[pages/LibraryPanel.tsx](../dashboard/src/pages/LibraryPanel.tsx)** | 馆藏管理页面:展现本地馆藏列表、最近阅读、同步状态、支持下载失败和“无资源”状态筛选。 |
| **[pages/ReaderPanel.tsx](../dashboard/src/pages/ReaderPanel.tsx)** | 对照阅读器视图:以 children 组合形式装配 `BilingualViewer``ReaderNotesSidebar`。 |
| **[pages/CitationPanel.tsx](../dashboard/src/pages/CitationPanel.tsx)** | 引文星系图谱视图:装配自研 Canvas 引文拓扑力导图。 |
| **[pages/SyncPanel.tsx](../dashboard/src/pages/SyncPanel.tsx)** | 批量同步控制页面:装配元数据同步面板、流水线批量任务日志流虚拟终端。 |
| **[pages/ResearchAgentPanel.tsx](../dashboard/src/pages/ResearchAgentPanel.tsx)** | 智能科研助理页面:装配 SSE 研讨消息列表、多模式选择、思维链展示与会话侧栏。 |
| **[components/](../dashboard/src/components/)** | 通用与业务子组件:如 Canvas 引擎 ([CitationGalaxyCanvas.tsx](../dashboard/src/components/CitationGalaxyCanvas.tsx))、下拉选择 ([CustomSelect.tsx](../dashboard/src/components/CustomSelect.tsx))、学术助手侧栏、智能体对话等。 |
| **[hooks/](../dashboard/src/hooks/)** | 全局与特定页面业务逻辑状态 Hook 库(如 `useLibrary`, `useSearch`, `useReaderState`, `useSyncState`, `useResearchAgent` 等),实现数据逻辑与 UI 渲染彻底解耦。 |
| **[types/index.ts](../dashboard/src/types/index.ts)** | 全局 TypeScript 静态类型定义中心。 |
---
+161 -17
View File
@@ -50,7 +50,34 @@ erDiagram
integer limit_count "拉取上限"
datetime last_run "最近运行时间"
datetime created_at "创建时间"
UNIQUE_query_source_limit "唯一去重约束"
}
PAPER_CHUNKS_CONTENT {
integer rowid PK
text bibcode FK
integer paragraph_index
text content
text headings "章节路径"
integer section_index "章节编号"
}
PAPER_TARGETS {
integer id PK
text bibcode FK
text target_name "标准化天体名称"
text ra "赤经"
text dec "赤纬"
real parallax "视差 mas"
text spectral_type "光谱分类"
real v_magnitude "视星等"
text aliases "JSON Array"
text otype "天体类型"
text oname "SIMBAD 主名称"
real pm_ra "自行 RA"
real pm_de "自行 Dec"
real radial_velocity "视向速度"
real parallax_err "视差误差"
text photometry "测光数据 JSON"
}
AGENT_SESSIONS {
@@ -58,7 +85,31 @@ erDiagram
text title
text model
integer turn_count
text last_error
text summary
text metadata
datetime deleted_at
integer rewind_count "回退计数"
text parent_session_id FK "分支来源"
text branch_metadata "分支元数据"
text mode "模式标识符"
}
AGENT_MESSAGES {
integer id PK
text session_id FK
integer turn_index
integer step_index
text role "system/user/assistant/tool"
text content
text thought "思考链"
text tool_calls "工具调用 JSON"
text tool_call_id "工具调用 ID"
integer token_count
text metadata
text raw_json
text agent_name "消息归属"
integer active "软删除标记"
}
AGENT_TASKS {
@@ -66,7 +117,7 @@ erDiagram
text session_id FK
text task_id
text content
text status
text status "pending/in_progress/completed"
text blocked_by "JSON Array — DAG 依赖"
text owner "分配目标 agent 名称"
}
@@ -92,9 +143,13 @@ erDiagram
PAPERS ||--o{ NOTES : "has"
PAPERS ||--o{ CITATIONS_REFERENCES : "cites / cited_by"
PAPERS ||--o{ PAPER_CHUNKS_CONTENT : "chunked into"
PAPERS ||--o{ PAPER_TARGETS : "contains"
AGENT_SESSIONS ||--o{ AGENT_MESSAGES : "contains"
AGENT_SESSIONS ||--o{ AGENT_TASKS : "owns"
AGENT_SESSIONS ||--o{ AGENT_AUDIT_LOG : "records"
AGENT_SESSIONS ||--o{ AGENT_TEAM_MEMBERS : "members"
AGENT_SESSIONS ||--o| AGENT_SESSIONS : "branches from"
```
---
@@ -127,44 +182,133 @@ erDiagram
存储用户保存的批量同步检索条件,支持快速重新同步。
- **唯一约束**`UNIQUE(query, source, limit_count)` 确保相同条件的检索不会重复保存。
### 2.5 agent_sessions 表 (Agent 会话)
存储 ReAct 智能体对话会话的元数据,支持软删除 (`deleted_at`)
- 每条会话关联 `agent_messages` 表存储对话历史与工具调用记录
- **索引**`idx_agent_sessions_created_at` (ORDER BY updated_at DESC)
### 2.5 paper_chunks_content 表 (RAG 文本切片)
存储文献 Markdown 段落的文本切片,用于向量嵌入和混合检索
- `rowid`:自增主键,与 `vec_paper_chunks` 虚拟表的 rowid 保持 1:1 对齐
- `headings`:章节路径,如 `"Introduction > Background"`,用于结构化检索
- `section_index`:章节内的段落编号。
- **外键**`bibcode` 级联删除 (`ON DELETE CASCADE`)。
- **关联 FTS5**`paper_chunks_fts` 虚拟表通过触发器自动同步 `content` 字段。
### 2.6 agent_tasks 表 (Agent 任务追踪)
### 2.6 paper_targets 表 (天体目标缓存)
存储从文献中提取并通过 CDS Sesame 解析的天体物理参数。
- `target_name`:标准化天体名称(如 `GD 358`)。
- `ra` / `dec`:赤道坐标(赤经/赤纬)。
- `parallax`:视差(mas,毫角秒)。
- `spectral_type`:光谱分类(如 `DA1`)。
- `otype` / `oname`:Sesame v4 返回的天体类型和 SIMBAD 官方主名称。
- `pm_ra` / `pm_de`:自行分量(mas/yr)。
- `radial_velocity`:视向速度。
- `photometry`:多波段测光数据(JSON 文本)。
- **唯一约束**`UNIQUE(bibcode, target_name)`
- **索引**`idx_paper_targets_name`
### 2.7 agent_sessions 表 (Agent 会话)
存储 ReAct 智能体对话会话的元数据。
- `deleted_at`:软删除时间戳(NULL 表示活跃会话)。
- `rewind_count`:会话回退(undo)次数,用于追踪重做历史。
- `parent_session_id`:分支来源会话 ID,支持会话分叉(branch)。
- `branch_metadata`:分支元数据(JSON 文本)。
- `mode`:会话模式标识符(`default``deep-research``literature-reader`),控制 Agent 的行为配置。
- **索引**`idx_agent_sessions_updated`WHERE deleted_at IS NULL,仅索引活跃会话)。
### 2.8 agent_messages 表 (Agent 消息)
存储 Agent 会话的完整对话历史,包括思考链和工具调用。
- `role``system` / `user` / `assistant` / `tool`
- `thought`LLM 思考链内容(CoT)。
- `tool_calls`:工具调用 JSON(函数名 + 参数)。
- `tool_call_id`:工具调用唯一标识(用于 SSE 流中 tool_call ↔ tool_result 配对)。
- `agent_name`:消息归属(`lead` / 子代理名 / teammate 名),支持身份隔离。
- `active`:软删除标记(`0` = 已回退隐藏,`1` = 正常可见),用于 session rewind。
- **索引**`idx_agent_messages_session``idx_agent_messages_turn``idx_agent_messages_agent``idx_agent_messages_active`
- **关联 FTS5**`agent_messages_fts` 虚拟表通过触发器自动同步 `content``thought``tool_calls` 字段。
### 2.9 agent_tasks 表 (Agent 任务追踪)
持久化智能体的结构化待办任务,支持 DAG 依赖模式。
- `blocked_by`:JSON 数组,前置任务 ID 列表。
- `status` 生命周期:`pending``in_progress``completed`
- `owner`:分配目标 agent 名称(多 Agent 团队协作路由)。
- **索引**`idx_agent_tasks_session``idx_agent_tasks_status``idx_agent_tasks_session_task` (UNIQUE)。
### 2.7 agent_audit_log 表 (Agent 工具审计)
### 2.10 agent_audit_log 表 (Agent 工具审计)
记录所有工具调用的审计信息:工具名称、执行状态、耗时 (ms)、输出预览。
- `status``OK` / `FAIL` / `SESSION_STOP`
- `agent_name`:区分 lead/子代理/teammate 的调用来源。
- **用途**`GET /api/chat/metrics` 聚合指标、会话审计回溯。
### 2.8 agent_team_members 表 (多 Agent 团队)
### 2.11 agent_team_members 表 (多 Agent 团队)
管理多智能体团队中每个成员的生命周期。
- `status``spawning``active``idle``shutdown`
- `agent_role`:区分 team lead / teammate 等角色。
- **唯一约束**`UNIQUE(session_id, agent_name)`
### 2.12 全文搜索 (FTS5)
系统在以下实体表上建立了 FTS5 全文索引,通过触发器自动保持同步:
| FTS5 虚拟表 | 实体表 | 索引字段 | 用途 |
|:---|:---|:---|:---|
| `papers_fts` | `papers` | title, authors, keywords, abstract, pub | 本地文献 BM25 全文检索 |
| `paper_chunks_fts` | `paper_chunks_content` | content | 段落级稀疏检索,配合 `vec_paper_chunks` 向量做混合搜索 |
| `agent_sessions_fts` | `agent_sessions` | session_id, title, summary, metadata | 会话历史搜索 |
| `agent_messages_fts` | `agent_messages` | session_id, role, content, thought, tool_calls | 对话内容搜索 |
每个 FTS5 虚拟表通过 `content='<实体表>'` 声明为外部内容表,并配套 `_insert``_update``_delete` 三个触发器保持数据同步。
---
## 3. 数据库迁移说明
迁移脚本存放在 `migrations/` 下,服务启动时(`src/main.rs`)会自动调用 `sqlx::migrate!().run(&pool).await` 自动部署:
### 3.1 迁移机制
迁移脚本存放在 `migrations/` 目录下,使用 `sqlx`**change-based 迁移** 模型:
- **编译期嵌入**`sqlx::migrate!("./migrations")` 宏在编译时将 `.sql` 文件嵌入二进制
- **启动时自动执行**`src/main.rs``src/bin/cli.rs` 以及所有测试的 in-memory 数据库在启动时调用 `.run(&pool)`,对比 `_sqlx_migrations` 追踪表,按版本号顺序执行未应用的迁移
- **版本号规则**:文件名格式 `YYYYMMDDHHMMSS_description.sql`,时间戳前缀保证全局唯一排序
- **幂等性**:所有 DDL 必须使用 `IF NOT EXISTS` / `IF EXISTS`,确保可重复执行
- **checksum 校验**sqlx 对每个迁移文件计算 SHA-256 校验和并存入 `_sqlx_migrations`;若文件内容在已应用后被修改,启动时将拒绝执行(防止 schema 漂移)
### 3.2 当前迁移
| 迁移文件 | 说明 |
|:---|:---|
| `20260608000000_init.sql` | 初始化 `papers``citations_references` 结构。 |
| `20260608000001_notes.sql` | 添加 `notes` 笔记高亮表,并为关联建立级联删除。 |
| `20260608000002_add_doctype.sql` | 为 `papers` 表新增 `doctype` 文献类型字段。 |
| `20260608000003_sync_features.sql` | 添加 `sync_queries` 同步检索条件表,支持唯一去重。 |
| `20260616000000_agent_tasks.sql` | 智能体任务持久化表,支持 DAG 依赖与状态生命周期。 |
| `20260617000000_agent_audit_log.sql` | 智能体工具调用审计日志表。 |
| `20260618000000_agent_identity.sql` | Agent 身份隔离:消息/审计归属、`agent_team_members` 团队注册表。 |
| `00000000000000_init.sql` | **完整初始化**:包含所有表、索引、FTS5 虚拟表及同步触发器,详见第 2 节各表结构。 |
> **注意**`vec_paper_chunks` 向量虚拟表由 `src/main.rs` 在迁移之后动态创建,维度由 `EMBEDDING_DIM` 环境变量控制(默认 1536),不在迁移文件中管理。
### 3.3 新增迁移
开发新功能需要变更数据库 schema 时:
1.`migrations/` 下新建文件,命名 `YYYYMMDDHHMMSS_<简短描述>.sql`(取当前时间)
2. 编写增量 SQL`ALTER TABLE ADD COLUMN``CREATE TABLE IF NOT EXISTS` 等)
3. 运行 `cargo build && cargo test` 验证
4. 更新本文档的 3.2 节和对应的表结构说明
**SQLite 约束**SQLite 不支持事务性 DDL 的全部语义,且 `ALTER TABLE` 能力有限(不支持 `DROP COLUMN``RENAME COLUMN` 等旧版本的常见操作)。新增字段时务必使用 `DEFAULT` 值以保证向后兼容。
### 3.4 迁移 Squash
开发期产生的增量迁移应在 **首次正式发布前** squash 为单一 `init.sql`,避免迁移文件线性膨胀。Squash 流程:
1. **导出完整 schema**`sqlite3 library/astro_research.db .schema`
2. **移除以下内容**
- `_sqlx_migrations` 表(sqlx 自动管理)
- `sqlite_sequence` 表(SQLite 内部表)
- `vec_paper_chunks` 及其关联内部表(由 main.rs 运行时创建)
- 所有 FTS5 内部表(`_data``_idx``_docsize``_config`,由 FTS5 自动管理)
3. **写入 `migrations/00000000000000_init.sql`**:确保所有 DDL 带 `IF NOT EXISTS` / `IF EXISTS`
4. **删除所有旧迁移文件**
5. **重建二进制**`cargo build`(新迁移文件需嵌入)
6. **更新已有数据库**(保留数据):
```sql
DELETE FROM _sqlx_migrations;
-- 重启应用后 sqlx 自动应用新的 init 迁移(所有 IF NOT EXISTS 均为 no-op
```
7. **验证**`cargo test --lib && cargo run`
> 本项目在 2026-06-25 执行了一次 squash,将 18 个开发期增量迁移合并为 1 个 `00000000000000_init.sql`,同时保留了已有的 1341 条文献记录和 6477 条引用关系。
---