feat: align local-first workspace direction

Document the VSCode-like local-first product shape, demote Convex to a control-plane role, and retire stale architecture drafts.

Add local workspace migration/export references plus smoke coverage for no-Convex managed workspace startup, local markdown title/body/options persistence, asset upload behavior, and Convex fixture export.

Verification: git diff --cached --check; node scripts/check-local-first-convex-guard.js --staged; node scripts/task444-convex-workspace-export-local-fixture-smoke.js; node scripts/task166-local-first-managed-workspace-no-convex-smoke.js; node scripts/task167-local-markdown-title-body-options-no-convex-smoke.js
This commit is contained in:
lix-2026
2026-05-19 08:11:58 +08:00
parent 68d321e297
commit cdff672aa5
67 changed files with 5242 additions and 932 deletions
+78 -129
View File
@@ -1,164 +1,113 @@
# 当前完整架构
> 更新时间:2026-05-17
> 更新时间:2026-05-19
>
> 范围:`/mnt/Data1T/mnote` 当前可见实现的完整架构、冲突口径、过渡态和缺失功能
> 范围:`/mnt/Data1T/mnote` 当前可见实现、主线口径、历史退役边界和后续功能缺口
## 1. 结论
## 1. 当前产品形态
当前系统已经形成一条清晰的主线
当前项目口径固定为
`Convex / 本地文件` -> `Rust kernel / bridge-runtime` -> `mnote-web` -> `前端壳与编辑器` -> `AI runtime`
> **MNote = VSCode 简化版工作区 + tiptap 的 Markdown 前端编辑器 + Hermes / Reasonix agent + simplemindmap / office 插件 + Wolai 主题 Web 壳 + 鉴权控制面。**
但它还不是单一真源闭环。现在同时存在三类并行真相
这意味着
1. `tree` / `page` / `resource` 的 Rust 语义真相。
2. 文档页与 Sidebar 的前端本地派生真相
3. AI 写入链路中的 markdown / block 双合同真相
- 本地 workspace folder 是早期产品默认数据真相。
- 本地 `.md` 文件是页面正文真相;Page Aggregate、tiptap state、AI context 都是投影或工作副本
- Rust kernel / projection / command 持有树、页面、资源和权限语义
- tiptap 是 Markdown 的前端显示与交互层,不是 agent 的主工作面。
- Hermes / Reasonix 默认应像 VSCode 中的 agent 一样,在授权目录白名单内用自身 patch / diff / 文件编辑能力修改文件。
- Convex / 服务端不再是默认正文、附件、AI 会话全文主存储,而是 auth、membership、share grants、sync state、AI policy、cloud source、compat 和 sync replica 控制面。
因此,项目当前更像“主线已经立住,但收口尚未完成”的状态,而不是“架构已统一完成”的状态。
上位设计已完成并迁入:
## 2. 分层架构
- [2-2 local-first workspace 与 Convex 控制面降级方案](/mnt/Data1T/mnote/design/02-convex-rust-long-term-architecture/done/2-2-local-first-workspace-convex-control-plane-v1.md)
### 2.1 事实存储
## 2. 当前分
- `Convex` 仍是在线协作、文档、媒体、树数据的实际后端存储底座。
- 本地 `.md` 文件是 `mnote.doc.fetch` / `mnote.doc.markdown_edit` 的另一条合法输入输出面。
- 本地文件路径与在线文档路径在工具层已经分叉,不能再假设只有一种存储后端。
### 2.1 Workspace / Storage
### 2.2 Kernel / Projection 层
- `local_folder` 是默认 source`/mnt/Data1T/Mnote_data/users/<actor>/workspaces/my-space/` 是受管“我的空间”默认根。
- 管理员通过控制面授权用户可读写目录;普通用户不能自助获得全盘读写。
- 上传到本地 Markdown 页面时,图片和附件默认写入 sibling assets,例如 `README.assets/image.png`,正文保存相对 Markdown 链接。
- Convex source 仍可作为 cloud / compat / sync replica,但新增功能不能默认把 `documents.*``mediaAssets.*``aiSessions.*` 当主存储。
- `rust/crates/core-protocol/src/kernel.rs` 定义 `KernelProjectionKind``KernelProjectionResourceKind``KernelObjectIdentity` 等协议语义。
- `rust/crates/bridge-runtime/src/lib.rs` 负责从 Convex 侧数据归一化出 kernel nodes / edges / projections,并生成 command plan。
- 语义主导权已经明显从前端迁到 Rust,但前端仍保留若干本地派生投影。
### 2.2 Rust Kernel / Projection
### 2.3 Tree / Command 层
- `core-protocol` 定义树、资源、页面、AI access scope、page body write 等协议语义。
- `bridge-runtime``mnote-web` 负责把 LocalFS / Convex / future sync source 归一成稳定 projection 与 command。
- 前端只消费 `file_tree``page_tree``page_aggregate`、tree command result 和少量 editor runtime payload。
- 正式命令面应落在 `tree.*``tree.resource.*`
- `mnote-web` 同时暴露 `tree` 命令路由与兼容/过渡路由。
- FileTree 资源行已与页面命令对象隔离:资源 owner 只作为上下文,`data-document-id` / 页面命令目标只保留给真正页面行。
### 2.3 Web Shell / Editor
### 2.4 Transport / Realtime 层
- `mnote-web` 是当前 3000 ownerNext / React 前端已退入 `recycle/`,只作为历史参考或 island bundle source。
- 文档页默认编辑 host 是页面内 `leptos-tiptap` island。
- local source 正文保存主入口已收口到带文件版本的 `page.body.write` / `/api/page-body/write``/api/documents/save` 只作为 compat adapter。
- 文件 watcher 发现 agent / 外部编辑器写入后,clean editor 自动刷新,dirty editor 进入冲突态,不静默覆盖。
- Rust Web 已同时注册 `/api/tree/events`SSE)与 `/api/realtime/ws`WS)两条实时链路([routes/mod.rs:170-172](rust/crates/mnote-web/src/routes/mod.rs:170))。
- Rust SSR 主壳([layout.rs](rust/crates/mnote-web/src/ssr/pages/layout.rs:7126))已内置 WS 消费者(`startWithWebSocket`),并在 WS 断开后自动切 SSE fallback`ws.onclose → startWithSseFallback`)。
- 当前默认 `bootstrap.transport` 已切到 `convex-command-log-ws`,主壳先走 WSSSE 保留为 fallback。
- `recycle/wolai-frontend`(已退役的 Next.js legacy 侧)仅使用 SSE,无 WS 消费者。
- WS 与 SSE 的 snapshot / delta 载荷合同已在 Rust 主壳消费层统一;后续重点是继续减少兼容 fallback 与 live cache 补偿链。
### 2.4 AI Runtime
### 2.5 Page Aggregate 层
- local-first 普通 Markdown 编辑主路径是:
- 文档页入口已经优先消费 Rust `page-aggregate` 快照。
- AI context 的 page subtree 已只读 Rust Page Aggregate 的稳定 projection,不再由前端本地构造第二份 page tree 真相。
- 当前 page aggregate 仍是从 `documents.content` / local markdown content 投影出来的过渡闭环,不是 EditorBlockDocument 原生单一真源闭环。
```text
当前页面定位到真实 .md 文件
-> MNote 计算登录用户 allowed roots / current file / selection
-> Hermes / Reasonix 在白名单目录内运行
-> agent 使用自身 patch / diff / 文件编辑能力写文件
-> MNote watcher / refresh 同步 Page Aggregate 与 tiptap
```
### 2.6 Editor Runtime 层
- `mnote.doc.fetch``mnote.doc.markdown_edit``mnote.doc.apply_block_ops``mnote.block.*``mnote.page.*` 保留为 cloud / remote agent / compat / 复杂结构辅助工具。
- `/api/page-ai/block-edit-workflow` 不再作为 local-first 普通正文编辑主路径。
- AI session 全文在 local source 下默认写入 `ai-sessions/private/*.jsonl``ai-sessions/shared/<share-id>/*.jsonl`Convex 只保存必要 metadata / audit / sync replica。
- 前端壳:Rust mnote-web 独享 3000 入口,通过 SSR 输出 workspace shell、文档壳、Sidebar、tree 等完整 HTML[gateway.rs](rust/crates/mnote-web/src/routes/gateway.rs:156)、[web_shell.rs](rust/crates/mnote-web/src/routes/web_shell.rs:63))。Next.js 前端代码已随 wolai-frontend 整体移入 `recycle/`,不再作为运行时 daemon 维护。
- `leptos-tiptap` island 已是文档页默认编辑 host,以 WASM 形式由 Rust SSR 加载。
- 保存正文仍会经过 `documents/save` 兼容面。
- 这意味着编辑器体验已经切主,但写回语义还没有完全切到唯一主命令面。
## 3. 已完成收口
### 2.7 AI Runtime 层
- Local-first workspace 上位设计和 checklist 已完成,迁入 `design/02-convex-rust-long-term-architecture/done/2-2-*`
- `cargo fmt --check --all``local_folder``hermes_tools`、local/shared AI session、local-first Convex guard、Convex export fixture、local asset upload smoke、external-change conflict smoke 均已作为 `2-2` 验收证据记录。
- 本地上传链路已避免 Convex media asset,落盘相对 Markdown 链接。
- 本地 AI 会话已区分 private / shared / cloud,并在 UI 上显示来源。
- Convex guard 已阻止 active 路径重新引入未标注的 Convex documents / media / aiSessions 默认主存储口径。
- `mnote.doc.fetch``mnote.doc.markdown_edit``mnote.doc.apply_block_ops``page_ai_workflow`、Hermes / ACP / Reasonix 构成当前 AI 主链。
- 简单正文编辑主路径已统一为模型生成 search/replace / full_content → `mnote.doc.markdown_edit` → 统一 mnote tool executor`mnote.doc.apply_block_ops` 保留为结构性块操作辅助。
- 工具权限、dryRun、幂等、revision / conflictDetectionKey、manifest schema、tool guidance、ACP payload / response 等 P0 合同漂移已收口;Phase C 的 review session / 流式 apply 仍冻结。
## 4. 仍在推进的功能缺口
## 3. 当前成立的事实与过渡态
1. **管理员目录授权 UI / API**
- 需要把 `access-policy.json` 和当前 auth actor、admin grant、read/write/share 权限做成可管理界面。
- 管理员可授权任意 canonical 目录;普通用户只能访问自己的受管 my-space 或被授权目录。
### 3.1 已成立事实
2. **VSCode-like 冲突处理 UI**
- 当前已有 clean/dirty watcher 行为和冲突态 smoke。
- 还需要做可用的“接受磁盘版本 / 保留当前版本 / 打开 diff 合并”交互。
- Rust 协议层已经成为语义主线,不再主要依赖前端拼装。
- Tree 主链已经从旧兼容入口退向 Rust Web
- 文档页主编辑器已经切到 `leptos-tiptap` island
- AI 页面编辑已经不再是纯前端本地逻辑。
- **前端壳已切换到 Rust**:默认 `desktop:hot` 仅启动 Rust mnote-web 作为 3000 网关 owner。`wolai-frontend`Next.js 前端)已移至 `recycle/`,不再作为运行时 daemon 或 legacy fallback 维护。
3. **agent 写入审计**
- local-first agent 应回收 changed files、diff summary、tool/run id、actor、workspace root、permission level
- audit 默认本地落盘,同步开启时再上报控制面
### 3.2 过渡态
4. **本地全文搜索、引用和索引**
- 本地 `.md` workspace 需要独立索引:全文搜索、反链、页面引用、资源引用、标签。
- 不能依赖 Convex search 才能搜索本地工作区。
- Page Aggregate 仍从 `documents.content` 侧 join 构造,而不是原生 EditorBlockDocument 真源。
- 页面正文写回仍经过兼容保存面,尚未完全切到唯一主命令面
- realtime / Page Aggregate / AI 写入的 P0 合同已基本收口,但兼容路由和历史 adapter 仍偏多
5. **分享与同步闭环**
- 需要把 share grants、shared workspace cache、shared AI session、只读/可写权限和冲突处理连成产品级闭环
- 控制面不可用时不得扩大本地缓存权限
## 4. 架构冲突矩阵
6. **插件资源模型**
- simplemindmap / office 应作为 Resource Tree 对象打开和保存。
- Markdown 中只保留链接或嵌入引用,不把复杂对象强塞进普通正文块。
### 4.1 Tree realtime
7. **旧 Convex 数据迁移产品化**
- 当前已有 fixture/offline 导出脚本。
- 后续需要真实 Convex workspace 导出入口、迁移进度、冲突报告、回滚/备份策略。
- 事实:Rust Web 同时注册 WS 与 SSE。
- 事实:Rust SSR 主壳默认以 WS 为主链,SSE 是断线 fallback。
- 当前状态:原“WS 文档口径 / 前端 SSE 实现”冲突已修复。
- 剩余风险:live cache 与兼容 fallback 仍需要继续瘦身,避免未来再次出现多链路补偿。
## 5. 已退役或降级口径
### 4.2 FileTree 资源行
以下说法不再作为当前主线:
- 事实:资源投影行带 `documentId`
- 事实:资源行的 owner document 与页面命令目标已分离,资源行不再暴露页面命令目标 ID。
- 当前状态:原“资源行被当成页面命令对象处理”冲突已修复。
- 剩余风险:资源对象的完整 `tree.resource.*` 命令面仍应继续补齐。
- “Convex 是默认正文 / 附件 / AI 会话全文主存储。”
- `mnote.doc.markdown_edit` 是 local-first 普通 Markdown 编辑唯一主路径。”
- “页面 AI 必须走 `/api/page-ai/block-edit-workflow``mnote.block.*` 才能改正文。”
- `/api/documents/save` 是长期正文保存主入口。”
- “BlockNote 是当前默认编辑器或系统事实源。”
- “Next App Router / wolai-frontend 是 3000 主运行时。”
### 4.3 Page Aggregate
- 事实:Rust snapshot 已是入口事实。
- 事实:AI context 的 page subtree 已只读 Rust Page Aggregate projection,外部 AI 写入后会同步本地 aggregate script。
- 当前状态:原“AI context / 文档页 / Rust Aggregate 多源抢真相”的 P0 问题已修复。
- 剩余风险:Page Aggregate 仍从 `documents.content` 投影,不是 EditorBlockDocument 原生落库真相。
### 4.4 AI 写入
- 事实:`markdown_edit` 已是简单正文编辑主路径。
- 事实:Hermes guidance、manifest、page_ai_workflow、tool executor、Reasonix ACP payload 已同步到同一合同。
- 当前状态:原“markdown / block / tool executor 三套合同漂移”的 P0 问题已修复。
- 剩余风险:复杂结构编辑仍应明确落到 `apply_block_ops` / `mnote.block.*`Phase C review / streaming apply 尚未实施。
## 5. 缺失功能
- Page Aggregate 仍缺 EditorBlockDocument 原生落库真相。
- 正文保存仍经过 `documents/save` 兼容面,唯一主命令面尚未完全闭环。
- `tree.resource.*` 仍需要补完整资源对象生命周期命令。
- 兼容路由、历史 adapter 与 fallback 仍偏多,需要继续减小长期维护面。
## 6. 推荐收口顺序
1. 先推进 Page Aggregate 原生 EditorBlockDocument 落库,减少 `documents.content` 投影过渡层。
2. 再收正文保存主命令面,把 `documents/save` 兼容写入逐步迁到正式页面 / 编辑器命令。
3. 再补齐 `tree.resource.*` 资源对象生命周期命令,避免资源操作长期停留在禁用或兼容态。
4. 最后清理兼容路由、历史 adapter 与 fallback,使 Rust kernel / Rust Web / SSR 主壳的合同成为唯一运行口径。
## 7. 相关审查与缺陷
- [设计审查:当前 mnote 项目 AI / Page Aggregate 定向 Review](./design/10-review/done/10-current-mnote-ai-runtime-review-v1.md)
- [设计审查:当前完整架构 Review](./design/10-review/done/11-current-full-architecture-review-v1.md)
## 8. 本次落档缺陷索引
### 8.1 Rust Web / Realtime / ACP
- [3-16 tree realtime WS 主链口径与前端 SSE 实现不一致](./bugs/03-rust-web/done/3-16-tree-realtime-ws-sse-doc-contract-drift-v1.md)
- [3-17 SSE push 模式跳过 polling safety net](./bugs/03-rust-web/done/3-17-sse-push-skips-polling-fallback-v1.md)
- [3-18 WS 与 SSE delta 载荷合同分裂](./bugs/03-rust-web/done/3-18-ws-sse-delta-contract-split-v1.md)
- [3-19 Reasonix ACP wrapper 调 mnote tool 缺少身份与幂等字段](./bugs/03-rust-web/done/3-19-acp-reasonix-tool-call-missing-identity-fields-v1.md)
- [3-20 ACP incoming request 只记录日志不响应](./bugs/03-rust-web/done/3-20-acp-request-permission-no-response-v1.md)
- [3-21 ACP run payload 被第一次 stream_events 消费后移除](./bugs/03-rust-web/done/3-21-acp-run-payload-consumed-and-removed-v1.md)
### 8.2 Tree Domain
- [4-46 FileTree 资源行被当成页面命令对象处理](./bugs/04-tree-domain/done/4-46-filetree-resource-row-document-command-leak-v1.md)
### 8.3 Editor Mainline
- [5-15 PageAggregateClientState 仍在前端生成第二份 page tree 真相](./bugs/05-editor-mainline/done/5-15-page-aggregate-client-state-second-truth-v1.md)
- [5-16 Sidebar preferred snapshot 中 query 可覆盖 live stream](./bugs/05-editor-mainline/done/5-16-sidebar-preferred-snapshot-query-overrides-live-stream-v1.md)
- [5-17 文档页标题优先 liveSidebarTitle 而非 Page Aggregate head](./bugs/05-editor-mainline/done/5-17-document-title-source-drift-live-sidebar-over-head-v1.md)
- [5-18 AI 写正文后本地 Page Aggregate content 可能不刷新](./bugs/05-editor-mainline/done/5-18-ai-write-body-does-not-sync-page-aggregate-content-v1.md)
### 8.4 AI
- [7-18 AI markdown_edit 阶段状态合同漂移](./bugs/07-ai/done/7-18-ai-markdown-edit-phase-state-contract-drift-v1.md)
- [7-19 Hermes 工具指导仍优先 apply_block_ops 而非 markdown_edit](./bugs/07-ai/done/7-19-hermes-tool-guidance-markdown-edit-contract-drift-v1.md)
- [7-20 page_ai_workflow 绕过 Hermes tool executor / audit / toggle](./bugs/07-ai/done/7-20-page-ai-workflow-bypasses-hermes-tool-executor-v1.md)
- [7-21 mnote.doc.markdown_edit 本地文件写入绕过 dryRun / idempotency](./bugs/07-ai/done/7-21-markdown-edit-local-write-contract-bypass-v1.md)
- [7-22 mnote.doc.apply_block_ops 批量写入缺少 revision / conflictDetectionKey 校验](./bugs/07-ai/done/7-22-apply-block-ops-missing-write-preconditions-v1.md)
- [7-23 mnote.doc.markdown_edit manifest schema 缺少 required 与写入字段](./bugs/07-ai/done/7-23-markdown-edit-manifest-schema-contract-drift-v1.md)
- [7-24 在线 markdown_edit 写回不以最终 Markdown 为真源](./bugs/07-ai/done/7-24-markdown-edit-online-write-does-not-use-final-markdown-v1.md)
- [7-25 ACP Reasonix 页面 AI block_edit_workflow 在 markdown 命中后生成空 block_ops](./bugs/07-ai/done/7-25-reasonix-block-edit-workflow-empty-block-ops-after-markdown-match-v1.md)
历史文件如果需要保留这些说法,必须明确标注为 `[recycle]`、legacy、review snapshot 或 compat / cloud source 背景。