623 lines
14 KiB
Markdown
623 lines
14 KiB
Markdown
# 03. Storage / Event / Indexing v0
|
||||
|
|
|
|||
|
|
更新时间:2026-04-11
|
|||
|
|
适用范围:`/mnt/Data1T/mnote-rust`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 目标
|
|||
|
|
|
|||
|
|
本文件定义 `mnote-rust` 在当前路线下的持久化、事件日志、索引体系。
|
|||
|
|
|
|||
|
|
它要回答:
|
|||
|
|
|
|||
|
|
- 当前系统事实层应落在哪里
|
|||
|
|
- Rust 内核怎样接入既有事实层而不重复造库
|
|||
|
|
- 写操作如何进入事件链路
|
|||
|
|
- 搜索、引用、RAG、回放、审计依赖什么数据面
|
|||
|
|
- 如何既保证性能,又保证 AI 可观测、可维护、可回放
|
|||
|
|
|
|||
|
|
这部分的前提必须先讲清:
|
|||
|
|
|
|||
|
|
> 对当前 `mnote` / `mnote-next` 主线来说,**Convex 仍是主事实层**。
|
|||
|
|
|
|||
|
|
因此,这份文档不再讨论“用 SQLite 取代 Convex 做主库”,而是讨论:
|
|||
|
|
|
|||
|
|
- 如何在 **Convex 主事实层** 之上建立 Rust 内核
|
|||
|
|
- 如何把索引、事件、导出、离线缓存、本地处理组织清楚
|
|||
|
|
- 如何避免再次引入第二套事实真相
|
|||
|
|
|
|||
|
|
如果这层设计不好,系统最终仍会退化成:
|
|||
|
|
|
|||
|
|
- 页面组件自己维护真相
|
|||
|
|
- 各类能力各写各的缓存
|
|||
|
|
- AI 看不到完整上下文
|
|||
|
|
- Rust 内核与现有系统各管一套数据
|
|||
|
|
- 回滚、审计、重建索引都变得困难
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 总原则
|
|||
|
|
|
|||
|
|
### 2.1 主事实层、事件日志、索引必须分层
|
|||
|
|
|
|||
|
|
三者职责不同:
|
|||
|
|
|
|||
|
|
- **主事实层**:保存系统当前真相
|
|||
|
|
- **事件日志**:保存“如何变成现在”的过程
|
|||
|
|
- **索引层**:为检索、聚合、推荐、RAG 提供加速读模型
|
|||
|
|
|
|||
|
|
禁止让任一层越权:
|
|||
|
|
|
|||
|
|
- 不能拿索引当真相
|
|||
|
|
- 不能只靠事件流而没有可直接读取的当前状态
|
|||
|
|
- 不能让页面缓存成为事实层
|
|||
|
|
- 不能让本地缓存演化成第二主库
|
|||
|
|
|
|||
|
|
### 2.2 当前主事实层应继续落在 Convex
|
|||
|
|
|
|||
|
|
基于 `mnote` 与 `mnote-next` 已有主线,当前阶段应坚持:
|
|||
|
|
|
|||
|
|
- **Convex 是唯一主事实层**
|
|||
|
|
- Rust 内核通过协议与 bridge 接入 Convex,而不是绕开它再建一套主库
|
|||
|
|
- 旧仓与新仓共享的核心对象,应优先复用既有 Convex schema / deployment / caller 体系
|
|||
|
|
|
|||
|
|
这不是保守,而是避免推翻已经跑通的主链路。
|
|||
|
|
|
|||
|
|
### 2.3 本地文件系统与本地嵌入式存储仍然重要
|
|||
|
|
|
|||
|
|
虽然主事实层继续用 Convex,但本地层仍然需要:
|
|||
|
|
|
|||
|
|
- **文件系统**:资产原文件、导出文件、缓存、派生产物、临时工作目录
|
|||
|
|
- **可选本地嵌入式存储**:离线缓存、索引快照、dry-run、调试态数据、临时队列
|
|||
|
|
|
|||
|
|
但这些都不能升级为新的主事实层。
|
|||
|
|
|
|||
|
|
### 2.4 写入必须原子化到“主事实层 + 事件落账”
|
|||
|
|
|
|||
|
|
一次命令成功后,至少要保证:
|
|||
|
|
|
|||
|
|
- 主事实层写入完成
|
|||
|
|
- 事件写入成功
|
|||
|
|
- 命令日志有记录
|
|||
|
|
|
|||
|
|
索引允许异步追平,但必须可检测 lag。
|
|||
|
|
|
|||
|
|
### 2.5 索引必须可重建
|
|||
|
|
|
|||
|
|
搜索索引、向量索引、聚合视图都必须满足:
|
|||
|
|
|
|||
|
|
- 可从主事实层 + 事件重新构建
|
|||
|
|
- 可做全量重建
|
|||
|
|
- 可做增量追平
|
|||
|
|
|
|||
|
|
否则后期会不可维护。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 三层数据面
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
[主事实层]
|
|||
|
|
Convex + FileSystem
|
|||
|
|
|
|||
|
|
[事件与日志层]
|
|||
|
|
CommandLog + DomainEvent + JobLog + AuditTrail
|
|||
|
|
|
|||
|
|
[索引与派生层]
|
|||
|
|
FTS / Reference Graph / Backlink View / Outline View / Vector Index
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.1 主事实层负责
|
|||
|
|
|
|||
|
|
- Workspace / Page / Block / Asset / Reference / Task / AgentSession 当前状态
|
|||
|
|
- 事务性写入
|
|||
|
|
- 读取当前真相
|
|||
|
|
- 提供稳定 schema
|
|||
|
|
- 承担权限与主对象约束
|
|||
|
|
|
|||
|
|
### 3.2 事件与日志层负责
|
|||
|
|
|
|||
|
|
- 记录命令与事件
|
|||
|
|
- 记录 actor、reason、scope、结果
|
|||
|
|
- 支持回放、审计、问题追踪
|
|||
|
|
- 作为索引增量更新输入
|
|||
|
|
|
|||
|
|
### 3.3 索引与派生层负责
|
|||
|
|
|
|||
|
|
- 全文搜索
|
|||
|
|
- 页面大纲
|
|||
|
|
- 反链
|
|||
|
|
- 资产片段搜索
|
|||
|
|
- RAG 检索读模型
|
|||
|
|
- 推荐 / 关系聚合
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 主事实层选型
|
|||
|
|
|
|||
|
|
## 4.1 当前阶段的明确结论
|
|||
|
|
|
|||
|
|
推荐:
|
|||
|
|
|
|||
|
|
- **Convex**:结构化主事实层
|
|||
|
|
- **File System**:存原始资产与大对象
|
|||
|
|
- **Rust bridge / protocol layer**:作为统一命令、查询、工具接入面
|
|||
|
|
|
|||
|
|
原因:
|
|||
|
|
|
|||
|
|
- 与 `mnote` 中“Convex 已完全替换 Supabase”的现实一致
|
|||
|
|
- 与 `mnote-next` 中“默认复用现有 Convex deployment / project”的路线一致
|
|||
|
|
- 复用现有 deployment、schema、自建与 AI 开发经验,避免重建第二套数据库主线
|
|||
|
|
- 更符合“复用成熟能力,重构边界,不做无意义重建”的迁移原则
|
|||
|
|
|
|||
|
|
## 4.2 本地嵌入式存储的正确定位
|
|||
|
|
|
|||
|
|
可以保留本地嵌入式存储,但只限于:
|
|||
|
|
|
|||
|
|
- CLI / Agent 的离线缓存
|
|||
|
|
- 全文索引引擎的本地数据文件
|
|||
|
|
- dry-run / scaffold / 调试态数据
|
|||
|
|
- 单机导入处理中的临时工作库
|
|||
|
|
|
|||
|
|
不能把它写成:
|
|||
|
|
|
|||
|
|
- 第二套主事实层
|
|||
|
|
- 与 Convex 并列的正式写入真相
|
|||
|
|
- 长期双写的核心业务库
|
|||
|
|
|
|||
|
|
## 4.3 不建议的中心方案
|
|||
|
|
|
|||
|
|
- 用 SQLite 取代 Convex 成为主真相
|
|||
|
|
- OnlyOffice / 第三方编辑器内部状态作为主真相
|
|||
|
|
- 仅事件溯源、无当前态表
|
|||
|
|
- 单纯 Markdown 文件散落 + 大量 sidecar 作为唯一结构源
|
|||
|
|
- 长期维护 Convex + SQLite 双事实源
|
|||
|
|
|
|||
|
|
这些都会让系统再次陷入边界混乱。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 主事实对象结构建议
|
|||
|
|
|
|||
|
|
这里讨论的是**领域对象结构**,不是要求新建第二套数据库。
|
|||
|
|
|
|||
|
|
## 5.1 结构原则
|
|||
|
|
|
|||
|
|
- 主对象必须能映射到现有 Convex schema
|
|||
|
|
- 单对象一组稳定字段或有限关联表
|
|||
|
|
- 避免过度 EAV
|
|||
|
|
- JSON 仅用于局部扩展字段,不替代主 schema
|
|||
|
|
|
|||
|
|
## 5.2 建议主对象
|
|||
|
|
|
|||
|
|
至少包含:
|
|||
|
|
|
|||
|
|
- `workspaces`
|
|||
|
|
- `pages`
|
|||
|
|
- `page_versions`(可选)
|
|||
|
|
- `blocks`
|
|||
|
|
- `block_relations`(可选,若不全放在 block 表中)
|
|||
|
|
- `assets`
|
|||
|
|
- `asset_versions`
|
|||
|
|
- `references`
|
|||
|
|
- `tasks`
|
|||
|
|
- `agent_sessions`
|
|||
|
|
- `command_logs`
|
|||
|
|
- `domain_events`
|
|||
|
|
- `jobs`
|
|||
|
|
- `job_logs`
|
|||
|
|
|
|||
|
|
这些对象应优先映射或扩展到现有 Convex 主线,而不是在新仓先落一套平行本地表。
|
|||
|
|
|
|||
|
|
## 5.3 blocks 对象建议
|
|||
|
|
|
|||
|
|
关键字段:
|
|||
|
|
|
|||
|
|
- `block_id`
|
|||
|
|
- `workspace_id`
|
|||
|
|
- `page_id`
|
|||
|
|
- `parent_block_id`
|
|||
|
|
- `sort_key`
|
|||
|
|
- `block_type`
|
|||
|
|
- `content_json`
|
|||
|
|
- `props_json`
|
|||
|
|
- `annotations_json`
|
|||
|
|
- `revision`
|
|||
|
|
- `deleted_at`
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
|
|||
|
|
- `sort_key` 建议支持稀疏排序,避免频繁全量重排
|
|||
|
|
- 软删除优于直接硬删,方便审计与恢复
|
|||
|
|
- `revision` 用于乐观并发控制
|
|||
|
|
|
|||
|
|
## 5.4 assets 对象建议
|
|||
|
|
|
|||
|
|
- `asset_id`
|
|||
|
|
- `workspace_id`
|
|||
|
|
- `asset_kind`
|
|||
|
|
- `mime_type`
|
|||
|
|
- `current_version_id`
|
|||
|
|
- `storage_strategy`
|
|||
|
|
- `status`
|
|||
|
|
- `metadata_json`
|
|||
|
|
|
|||
|
|
## 5.5 references 对象建议
|
|||
|
|
|
|||
|
|
- `reference_id`
|
|||
|
|
- `source_object_type`
|
|||
|
|
- `source_object_id`
|
|||
|
|
- `target_object_type`
|
|||
|
|
- `target_object_id`
|
|||
|
|
- `anchor_json`
|
|||
|
|
- `ref_kind`
|
|||
|
|
- `status`
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 文件系统布局建议
|
|||
|
|
|
|||
|
|
资产不要全塞数据库 blob。
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
|
|||
|
|
```text
|
|||
|
|
workspace-data/
|
|||
|
|
├─ assets/
|
|||
|
|
│ ├─ asset_xxx/
|
|||
|
|
│ │ ├─ v1/original.docx
|
|||
|
|
│ │ ├─ v2/original.docx
|
|||
|
|
│ │ ├─ extracted/outline.json
|
|||
|
|
│ │ ├─ extracted/text.md
|
|||
|
|
│ │ └─ derived/preview.png
|
|||
|
|
├─ indexes/
|
|||
|
|
│ ├─ fts/
|
|||
|
|
│ └─ vector/
|
|||
|
|
├─ runtime/
|
|||
|
|
│ ├─ jobs/
|
|||
|
|
│ ├─ sessions/
|
|||
|
|
│ └─ temp/
|
|||
|
|
└─ export/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
原则:
|
|||
|
|
|
|||
|
|
- 结构化真相仍以 Convex 为主
|
|||
|
|
- 原始大文件入文件系统
|
|||
|
|
- 派生产物有明确目录归属
|
|||
|
|
- 临时文件与正式资产分离
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. Command Log
|
|||
|
|
|
|||
|
|
`CommandLog` 是所有写命令的正式记录。
|
|||
|
|
|
|||
|
|
### 7.1 最低字段
|
|||
|
|
|
|||
|
|
- `command_log_id`
|
|||
|
|
- `command_name`
|
|||
|
|
- `actor_type`
|
|||
|
|
- `actor_id`
|
|||
|
|
- `source`
|
|||
|
|
- `workspace_id`
|
|||
|
|
- `target_objects`
|
|||
|
|
- `payload_summary`
|
|||
|
|
- `refs_json`
|
|||
|
|
- `idempotency_key`
|
|||
|
|
- `status`
|
|||
|
|
- `created_at`
|
|||
|
|
- `finished_at`
|
|||
|
|
|
|||
|
|
### 7.2 设计要求
|
|||
|
|
|
|||
|
|
- 能关联到一次真实主写入
|
|||
|
|
- 能关联后续 domain events
|
|||
|
|
- 能关联 tool call / job / rollback
|
|||
|
|
- 能为 AI 回放与人类审计提供最小闭包
|
|||
|
|
|
|||
|
|
### 7.3 与 Convex 的关系
|
|||
|
|
|
|||
|
|
命令日志可以:
|
|||
|
|
|
|||
|
|
- 直接进入 Convex 主线对象
|
|||
|
|
- 或通过 bridge 落到与主对象同一事实层
|
|||
|
|
|
|||
|
|
但不要单独把命令日志只记在本地、主对象却记在远端;那会破坏统一审计链路。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. Domain Event
|
|||
|
|
|
|||
|
|
`DomainEvent` 不是为了炫技,而是为了:
|
|||
|
|
|
|||
|
|
- 给索引层提供标准增量输入
|
|||
|
|
- 给回放和审计提供结构化事件
|
|||
|
|
- 给异步任务提供稳定订阅源
|
|||
|
|
|
|||
|
|
### 8.1 事件最低字段
|
|||
|
|
|
|||
|
|
- `event_id`
|
|||
|
|
- `workspace_id`
|
|||
|
|
- `aggregate_type`
|
|||
|
|
- `aggregate_id`
|
|||
|
|
- `event_type`
|
|||
|
|
- `event_version`
|
|||
|
|
- `payload_json`
|
|||
|
|
- `command_log_id`
|
|||
|
|
- `actor_type`
|
|||
|
|
- `created_at`
|
|||
|
|
|
|||
|
|
### 8.2 事件边界
|
|||
|
|
|
|||
|
|
建议记录领域事件,而不是 UI 手势。
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
- `page_created`
|
|||
|
|
- `page_renamed`
|
|||
|
|
- `block_inserted`
|
|||
|
|
- `block_moved`
|
|||
|
|
- `block_content_replaced`
|
|||
|
|
- `asset_version_added`
|
|||
|
|
- `reference_created`
|
|||
|
|
- `task_status_changed`
|
|||
|
|
|
|||
|
|
不建议记录:
|
|||
|
|
|
|||
|
|
- 弹窗打开
|
|||
|
|
- 光标移动
|
|||
|
|
- hover 展示
|
|||
|
|
- 面板折叠
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. Job 与异步链路
|
|||
|
|
|
|||
|
|
不是所有事情都应进主事务。
|
|||
|
|
|
|||
|
|
应把这些放入 Job:
|
|||
|
|
|
|||
|
|
- OCR
|
|||
|
|
- OnlyOffice 提取/转换
|
|||
|
|
- 向量切片与嵌入
|
|||
|
|
- 全量重建索引
|
|||
|
|
- 大文件导入
|
|||
|
|
- 外部同步
|
|||
|
|
|
|||
|
|
### 9.1 Job 最低字段
|
|||
|
|
|
|||
|
|
- `job_id`
|
|||
|
|
- `job_type`
|
|||
|
|
- `workspace_id`
|
|||
|
|
- `target_objects`
|
|||
|
|
- `input_json`
|
|||
|
|
- `status`
|
|||
|
|
- `progress`
|
|||
|
|
- `error`
|
|||
|
|
- `created_at`
|
|||
|
|
- `started_at`
|
|||
|
|
- `finished_at`
|
|||
|
|
|
|||
|
|
### 9.2 不能放进主事务的内容
|
|||
|
|
|
|||
|
|
- 大模型推理
|
|||
|
|
- OCR
|
|||
|
|
- 大文件转换
|
|||
|
|
- 向量重建
|
|||
|
|
- 远程同步
|
|||
|
|
|
|||
|
|
这些必须走 Job。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10. 索引体系
|
|||
|
|
|
|||
|
|
## 10.1 Full Text Search
|
|||
|
|
|
|||
|
|
最低必做:
|
|||
|
|
|
|||
|
|
- 页面标题全文检索
|
|||
|
|
- 块内容全文检索
|
|||
|
|
- 资产提取文本全文检索
|
|||
|
|
- 引用 snippet 检索
|
|||
|
|
|
|||
|
|
建议:
|
|||
|
|
|
|||
|
|
- 初期直接用本地全文索引引擎(如 SQLite FTS5、Tantivy 或兼容方案)
|
|||
|
|
- 索引文档单位统一为“可定位对象”
|
|||
|
|
|
|||
|
|
例如:
|
|||
|
|
|
|||
|
|
- page
|
|||
|
|
- block
|
|||
|
|
- asset_fragment
|
|||
|
|
- reference_snippet
|
|||
|
|
|
|||
|
|
### 10.2 为什么块级索引重要
|
|||
|
|
|
|||
|
|
因为你的产品最终不是“整篇文档搜索”,而是:
|
|||
|
|
|
|||
|
|
- 找到某一段
|
|||
|
|
- 跳回块位置
|
|||
|
|
- 让 AI 只编辑局部
|
|||
|
|
- 给引用与上下文最小闭包
|
|||
|
|
|
|||
|
|
## 10.3 Reference Graph
|
|||
|
|
|
|||
|
|
必须维护引用图读模型:
|
|||
|
|
|
|||
|
|
- page -> page
|
|||
|
|
- block -> block
|
|||
|
|
- block -> asset fragment
|
|||
|
|
- task -> source object
|
|||
|
|
|
|||
|
|
这对:
|
|||
|
|
|
|||
|
|
- 反链
|
|||
|
|
- 影响面分析
|
|||
|
|
- AI 上下文组装
|
|||
|
|
- 知识导航
|
|||
|
|
|
|||
|
|
都很关键。
|
|||
|
|
|
|||
|
|
## 10.4 Outline View
|
|||
|
|
|
|||
|
|
页面大纲、Office 文档提取大纲、PDF 目录、Mindmap 树都应是派生读模型。
|
|||
|
|
|
|||
|
|
优点:
|
|||
|
|
|
|||
|
|
- 不污染主事实层
|
|||
|
|
- 允许多种提取策略
|
|||
|
|
- 容易重建
|
|||
|
|
|
|||
|
|
## 10.5 Vector Index
|
|||
|
|
|
|||
|
|
向量索引建议延后,但结构上预留。
|
|||
|
|
|
|||
|
|
原则:
|
|||
|
|
|
|||
|
|
- 向量索引只是检索加速层
|
|||
|
|
- 向量 chunk 必须能回指 `page_id / block_id / asset_id / anchor`
|
|||
|
|
- 向量索引失效可重建,不影响系统主真相
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11. 索引更新策略
|
|||
|
|
|
|||
|
|
## 11.1 起步建议:异步增量 + 可全量重建
|
|||
|
|
|
|||
|
|
每次事件提交后:
|
|||
|
|
|
|||
|
|
- 生成索引任务
|
|||
|
|
- 按对象粒度增量更新
|
|||
|
|
- 记录 lag 与最后处理 event id
|
|||
|
|
|
|||
|
|
## 11.2 索引一致性要求
|
|||
|
|
|
|||
|
|
- 主事实层一致性 > 索引实时性
|
|||
|
|
- 查询可返回“索引处理中”状态
|
|||
|
|
- 对必须强一致的局部场景,可同步刷新小范围索引
|
|||
|
|
|
|||
|
|
## 11.3 失败恢复
|
|||
|
|
|
|||
|
|
索引 worker 挂了也不能影响主写入。
|
|||
|
|
|
|||
|
|
必须支持:
|
|||
|
|
|
|||
|
|
- 从 `last_processed_event_id` 继续追平
|
|||
|
|
- 指定对象重建
|
|||
|
|
- 指定 workspace 全量重建
|
|||
|
|
|
|||
|
|
### 11.4 回放与索引重建的正式入口
|
|||
|
|
|
|||
|
|
从 task-034 开始,回放和重建不再只是“库里有个纯函数”,而要成为统一命令面的一部分。
|
|||
|
|
|
|||
|
|
最小要求:
|
|||
|
|
|
|||
|
|
- `event_replay`:从统一事件列表读取,输出 replay 后的 `cursor` 与受影响 event 摘要
|
|||
|
|
- `index_rebuild`:基于 `last_processed_event_id` / `last_processed_at` 重建索引批次,并返回新的 cursor
|
|||
|
|
- 两者都复用同一套 `request_id`、`trace_id`、`workspace_id`、`command_id` 语义,不允许临时脚本私有解释
|
|||
|
|
|
|||
|
|
这意味着后续无论是 CLI、AI 还是 Web 排障,都应先调用同一条 Rust 恢复命令面,而不是各自写一套索引补数脚本。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 12. AI 可观测性
|
|||
|
|
|
|||
|
|
AI 全流程介入后,系统必须能回答:
|
|||
|
|
|
|||
|
|
- 某次回答引用了哪些对象
|
|||
|
|
- 某次编辑基于哪些上下文
|
|||
|
|
- 某个工具为什么失败
|
|||
|
|
- 当前搜索索引是否滞后
|
|||
|
|
- 哪些对象正在被长任务处理
|
|||
|
|
|
|||
|
|
因此建议额外维护:
|
|||
|
|
|
|||
|
|
### 12.1 AgentSession 关联表
|
|||
|
|
|
|||
|
|
- `agent_session_objects`
|
|||
|
|
- `agent_session_tool_calls`
|
|||
|
|
- `agent_session_outputs`
|
|||
|
|
|
|||
|
|
### 12.2 Tool Call Log
|
|||
|
|
|
|||
|
|
记录:
|
|||
|
|
|
|||
|
|
- tool name
|
|||
|
|
- input
|
|||
|
|
- output summary
|
|||
|
|
- duration
|
|||
|
|
- error
|
|||
|
|
- command_log_id / query trace id
|
|||
|
|
|
|||
|
|
这样后期 AI 排障、回放、评估都会容易很多。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 13. 性能关键点
|
|||
|
|
|
|||
|
|
### 13.1 不要整页全文重写
|
|||
|
|
|
|||
|
|
编辑块时,只更新相关块与局部派生视图。
|
|||
|
|
|
|||
|
|
### 13.2 不要同步重建全索引
|
|||
|
|
|
|||
|
|
任何全库重建都必须后台化。
|
|||
|
|
|
|||
|
|
### 13.3 资产处理走异步
|
|||
|
|
|
|||
|
|
OCR、Office 转换、预览图生成、向量切片都不能阻塞主编辑事务。
|
|||
|
|
|
|||
|
|
### 13.4 读写模型分离
|
|||
|
|
|
|||
|
|
高频 UI 读需求可通过派生视图优化,不要污染主事实 schema。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 14. OnlyOffice 在存储层的正确位置
|
|||
|
|
|
|||
|
|
OnlyOffice 相关对象建议这样落地:
|
|||
|
|
|
|||
|
|
- 原始 `docx/xlsx/pptx/pdf`:作为 `Asset` + `AssetVersion`
|
|||
|
|
- 文档编辑结果:生成新 `AssetVersion`
|
|||
|
|
- 提取结构(目录、批注、书签、文本片段):作为派生读模型或 `Reference`
|
|||
|
|
- 当前选区、当前页码:作为短生命周期 `SelectionAnchor`
|
|||
|
|
|
|||
|
|
不要把:
|
|||
|
|
|
|||
|
|
- OnlyOffice 内部文档状态
|
|||
|
|
- 插件瞬时 UI 状态
|
|||
|
|
- callback 的临时 payload
|
|||
|
|
|
|||
|
|
直接当成主事实层。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 15. 迁移建议
|
|||
|
|
|
|||
|
|
先做:
|
|||
|
|
|
|||
|
|
1. 盘点现有 Convex schema 与 `mnote-rust` 领域对象的映射
|
|||
|
|
2. 落 `CommandLog / DomainEvent` 的主事实层方案
|
|||
|
|
3. 落 `Page / Block / Asset / Reference` 的 bridge / repo 接口
|
|||
|
|
4. 建立全文索引最小实现
|
|||
|
|
5. 建立索引 worker 骨架
|
|||
|
|
|
|||
|
|
再做:
|
|||
|
|
|
|||
|
|
6. AgentSession / ToolCallLog
|
|||
|
|
7. Outline / Backlink 读模型
|
|||
|
|
8. 向量索引占位
|
|||
|
|
9. Office / OCR / Mindmap 派生索引
|
|||
|
|
10. 必要的离线缓存 / dry-run 本地层
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 16. 一句话结论
|
|||
|
|
|
|||
|
|
`mnote-rust` 当前应采用 **Convex 主事实层 + FileSystem 资产存储 + CommandLog/DomainEvent 事件链路 + 可重建全文/引用/向量索引** 的分层结构;
|
|||
|
|
Rust 内核负责把命令、查询、工具、索引、异步任务与外部能力重新组织清楚,而不是再造一套与现有主线并列的数据库事实源。
|