AstroResearch/docs/database.md
Asfmq 5db4cc5998 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 (文献信息渲染)
2026-06-25 23:45:37 +08:00

14 KiB
Raw Blame History

AstroResearch Database Schema / 数据库设计

AstroResearch 使用轻量级、零配置的 SQLite 数据库作为持久化存储。数据库文件默认保存在项目根目录下的 astro_research.db(可通过 .env 中的 DATABASE_URL 配置),由 Rust 中的 sqlx 驱动管理并自动执行迁移。


1. 实体关系图 (Entity-Relationship Diagram)

erDiagram
    PAPERS {
        text bibcode PK
        text title
        text authors "JSON Array"
        text year
        text pub "Journal/Publisher"
        text keywords "JSON Array"
        text abstract
        text doi
        text arxiv_id
        integer citation_count
        integer reference_count
        text doctype "文献类型"
        text pdf_path "PDF 物理路径 或 error:诊断"
        text html_path "HTML 物理路径 或 error:诊断"
        text markdown_path "Markdown 物理路径"
        text translation_path "翻译文件物理路径"
        datetime created_at
    }

    NOTES {
        integer id PK
        text bibcode FK
        integer paragraph_index
        text note_text
        text highlight_color
        text selected_text
        datetime created_at
    }

    CITATIONS_REFERENCES {
        text source_bibcode PK
        text target_bibcode PK
    }

    SYNC_QUERIES {
        integer id PK
        text query "检索关键词"
        text source "数据源"
        integer limit_count "拉取上限"
        datetime last_run "最近运行时间"
        datetime created_at "创建时间"
    }

    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 {
        text session_id PK
        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 {
        integer id PK
        text session_id FK
        text task_id
        text content
        text status "pending/in_progress/completed"
        text blocked_by "JSON Array — DAG 依赖"
        text owner "分配目标 agent 名称"
    }

    AGENT_AUDIT_LOG {
        integer id PK
        text session_id FK
        integer step
        text tool_name
        text status "OK / FAIL / SESSION_STOP"
        integer elapsed_ms
        text output_preview
        text agent_name
    }

    AGENT_TEAM_MEMBERS {
        integer id PK
        text session_id FK
        text agent_name
        text agent_role
        text status "spawning / active / idle / shutdown"
    }

    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"

2. 数据表结构详述 (Table Schema Details)

2.1 papers 表 (文献元数据)

存储文献的核心元数据和本地物理存储路径。

  • 特殊字段说明
    • pdf_path / html_path:正常情况下存储相对路径(如 library/PDF/2024arXiv.pdf)。当下载失败时,会以 error: 前缀存储诊断信息(如 error:Cloudflare 拦截)。特殊值 error:no_resource 表示用户手动标记了"无有效全文资源"。
    • doctype:文献类型标识,如 articleeprintproceedingsphdthesiscatalogsoftwarecircularbook 等。
  • 索引
    • idx_papers_doi -> 基于 doi
    • idx_papers_arxiv_id -> 基于 arxiv_id

2.2 citations_references 表 (引文与参考文献拓扑)

多对多关联表,存储文献之间的引用网络(即拓扑星系图的基础数据)。

  • 复合主键(source_bibcode, target_bibcode)
  • 索引
    • idx_citations_ref_source -> 优化以 source_bibcode 查询参考文献
    • idx_citations_ref_target -> 优化以 target_bibcode 查询被引文献

2.3 notes 表 (高亮与阅读笔记)

存储学者在阅读器中对特定段落创建的高亮和笔记。

  • 外键bibcode 级联删除 (ON DELETE CASCADE)。
  • 索引
    • idx_notes_bibcode -> 优化单篇文献的笔记列表查询。

2.4 sync_queries 表 (同步检索条件)

存储用户保存的批量同步检索条件,支持快速重新同步。

  • 唯一约束UNIQUE(query, source, limit_count) 确保相同条件的检索不会重复保存。

2.5 paper_chunks_content 表 (RAG 文本切片)

存储文献 Markdown 段落的文本切片,用于向量嵌入和混合检索。

  • rowid:自增主键,与 vec_paper_chunks 虚拟表的 rowid 保持 1:1 对齐。
  • headings:章节路径,如 "Introduction > Background",用于结构化检索。
  • section_index:章节内的段落编号。
  • 外键bibcode 级联删除 (ON DELETE CASCADE)。
  • 关联 FTS5paper_chunks_fts 虚拟表通过触发器自动同步 content 字段。

2.6 paper_targets 表 (天体目标缓存)

存储从文献中提取并通过 CDS Sesame 解析的天体物理参数。

  • target_name:标准化天体名称(如 GD 358)。
  • ra / dec:赤道坐标(赤经/赤纬)。
  • parallax视差mas毫角秒
  • spectral_type:光谱分类(如 DA1)。
  • otype / onameSesame 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:会话模式标识符(defaultdeep-researchliterature-reader),控制 Agent 的行为配置。
  • 索引idx_agent_sessions_updatedWHERE deleted_at IS NULL仅索引活跃会话

2.8 agent_messages 表 (Agent 消息)

存储 Agent 会话的完整对话历史,包括思考链和工具调用。

  • rolesystem / user / assistant / tool
  • thoughtLLM 思考链内容CoT
  • tool_calls:工具调用 JSON函数名 + 参数)。
  • tool_call_id:工具调用唯一标识(用于 SSE 流中 tool_call ↔ tool_result 配对)。
  • agent_name:消息归属(lead / 子代理名 / teammate 名),支持身份隔离。
  • active:软删除标记(0 = 已回退隐藏,1 = 正常可见),用于 session rewind。
  • 索引idx_agent_messages_sessionidx_agent_messages_turnidx_agent_messages_agentidx_agent_messages_active
  • 关联 FTS5agent_messages_fts 虚拟表通过触发器自动同步 contentthoughttool_calls 字段。

2.9 agent_tasks 表 (Agent 任务追踪)

持久化智能体的结构化待办任务,支持 DAG 依赖模式。

  • blocked_byJSON 数组,前置任务 ID 列表。
  • status 生命周期:pendingin_progresscompleted
  • owner:分配目标 agent 名称(多 Agent 团队协作路由)。
  • 索引idx_agent_tasks_sessionidx_agent_tasks_statusidx_agent_tasks_session_task (UNIQUE)。

2.10 agent_audit_log 表 (Agent 工具审计)

记录所有工具调用的审计信息:工具名称、执行状态、耗时 (ms)、输出预览。

  • statusOK / FAIL / SESSION_STOP
  • agent_name:区分 lead/子代理/teammate 的调用来源。
  • 用途GET /api/chat/metrics 聚合指标、会话审计回溯。

2.11 agent_team_members 表 (多 Agent 团队)

管理多智能体团队中每个成员的生命周期。

  • statusspawningactiveidleshutdown
  • 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. 数据库迁移说明

3.1 迁移机制

迁移脚本存放在 migrations/ 目录下,使用 sqlxchange-based 迁移 模型:

  • 编译期嵌入sqlx::migrate!("./migrations") 宏在编译时将 .sql 文件嵌入二进制
  • 启动时自动执行src/main.rssrc/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 当前迁移

迁移文件 说明
00000000000000_init.sql 完整初始化包含所有表、索引、FTS5 虚拟表及同步触发器,详见第 2 节各表结构。

注意vec_paper_chunks 向量虚拟表由 src/main.rs 在迁移之后动态创建,维度由 EMBEDDING_DIM 环境变量控制(默认 1536不在迁移文件中管理。

3.3 新增迁移

开发新功能需要变更数据库 schema 时:

  1. migrations/ 下新建文件,命名 YYYYMMDDHHMMSS_<简短描述>.sql(取当前时间)
  2. 编写增量 SQLALTER TABLE ADD COLUMNCREATE TABLE IF NOT EXISTS 等)
  3. 运行 cargo build && cargo test 验证
  4. 更新本文档的 3.2 节和对应的表结构说明

SQLite 约束SQLite 不支持事务性 DDL 的全部语义,且 ALTER TABLE 能力有限(不支持 DROP COLUMNRENAME COLUMN 等旧版本的常见操作)。新增字段时务必使用 DEFAULT 值以保证向后兼容。

3.4 迁移 Squash

开发期产生的增量迁移应在 首次正式发布前 squash 为单一 init.sql避免迁移文件线性膨胀。Squash 流程:

  1. 导出完整 schemasqlite3 library/astro_research.db .schema
  2. 移除以下内容
    • _sqlx_migrationssqlx 自动管理)
    • sqlite_sequenceSQLite 内部表)
    • 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. 更新已有数据库(保留数据):
    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 条引用关系。


4. 错误诊断存储约定

系统使用 papers 表的 pdf_pathhtml_path 字段的双重语义来同时存储正常路径和错误诊断:

字段值模式 含义 前端展示
NULL 尚未尝试下载 琥珀色"未下载"角标
library/PDF/xxx.pdf 下载成功,正常物理路径 蓝色"已下载"角标
error:具体原因 下载失败,原因为前缀后的文本 红色"下载失败"角标,悬浮显示原因
error:no_resource 用户手动标记为无有效全文资源 灰色"无资源"角标

health_check 工具在 --fix 模式下会清理损坏文件并将路径重置为 NULL,但不会清除 error: 前缀的记录(以保留诊断线索)。