内容
<p align="center">
<img src="/public/favicon-light.svg" alt="Dotflowy" width="120" height="120" />
</p>
<h1 align="center">Dotflowy (测试版)</h1>
<p align="center">
<strong>无限思维导图,记录你的想法和任务</strong><br/>
<span>如果 Workflowy 是开源的,并且具有 Obsidian 插件的可扩展性</span>
</p>
<p align="center">
<a href="https://app.dotflowy.com"><strong>app.dotflowy.com</strong></a>
</p>
---
使用 [TanStack Start](https://tanstack.com/start) 和 [TanStack DB](https://tanstack.com/db) 构建。
核心本地化,支持通过 Cloudflare 部署,实现跨设备大纲同步,基于用户身份验证的 [Durable Object](https://developers.cloudflare.com/durable-objects/),支持邮件和密码登录 ([Better Auth](https://www.better-auth.com))。












## 状态
你的大纲存储在 TanStack DB 集合中。默认情况下,通过用户专属的 **Cloudflare Durable Object** (其附带的 SQLite 数据库)支持,写入操作通过 `/api/nodes`,实时读取通过 `/api/sync`(WebSocket)实现,因此在多个标签页或设备上编辑内容时无需重新聚焦。详见 [同步设计](docs/adr/0008-sync-via-a-per-user-durable-object.md)。扁平数据模型意味着更换后端只需更改集合选项,而无需重写代码。
当前功能:
- 支持嵌套项目符号和内联编辑;可折叠/展开子树(鼠标悬停在标尺上)
- 将任意项目符号作为临时根节点(点击其圆点),并带有返回上一级的导航条
- 任务:复选框标记完成状态;“显示已完成”切换隐藏已完成的项目
- 拖动项目符号的圆点即可重新排序 **和** 重新父级(鼠标 + 触摸)
- Markdown 风格的富文本:`内联代码`、`[链接](https://…)` 会折叠为干净的标签,以及 `#标签`
- 点击 `#标签` 会在原地过滤大纲;右键单击标签可为其着色
- 书签(头部星号固定当前缩放视图)和 `Cmd/Ctrl+K` 快速切换器,可跳转到任意位置
- `/` 命令面板(待办事项、普通项目符号、移动) 和 移动到对话框
- 暗黑模式、撤销/重做
- MCP 服务器(`/mcp`,OAuth 网关),允许 AI 代理读取和编辑大纲 — 添加到今天的日记、镜像节点、搜索 — 并与打开的编辑器实时同步
### 快捷键
| 键 | 操作 |
|---|---|
| `Enter` | 在插入符号处下方新建一个兄弟节点(在展开的项目符号末尾添加子节点) |
| `Tab` / `Shift+Tab` | 增大/减小缩进 |
| `Cmd/Ctrl+Shift+↑` / `↓` | 在兄弟节点之间移动;到达边缘时,移至父节点的相邻兄弟节点 |
| `Cmd/Ctrl+↑` / `↓` | 折叠/展开 |
| `Cmd/Ctrl+Enter` 或 `Cmd/Ctrl+D` | 切换完成状态 |
| `Cmd/Ctrl+.` / `Cmd/Ctrl+,` | 放大/缩小 |
| 空项目符号上的 `Backspace` | 删除它并聚焦到前一个项目符号 |
| 行边缘的 `Arrow ↑` / `↓` | 在项目符号之间移动(保留插入符号列) |
| `Cmd/Ctrl+Z` / `Cmd/Ctrl+Shift+Z` | 撤销/重做 |
| `Cmd/Ctrl+K` | 打开快速切换器 |
待实现功能:分享、电子邮件验证。
## 技术栈
| 层 | 选择 | 原因 |
|---|---|---|
| 框架 | TanStack Start (SPA 模式) | 基于文件的路由,无需 SSR |
| 数据 | TanStack DB 查询集合,基于用户专属 Durable Object | 乐观突变、模式验证;扁平模型通过更改集合选项更换后端 |
| 后端 | Cloudflare Worker + Durable Objects | 一个 Worker 提供 SPA 并路由 `/api/nodes` + `/api/kv` 同步 API 到用户专属 Durable Object |
| 认证 | Better Auth(邮件 + 密码) | 自助注册;其 `user` 表是身份存储,`user.id` 键入每个用户的 DO。D1 中的会话 |
| 验证 | Effect Schema | 标准模式兼容(通过 `toStandardSchemaV1`);驱动集合的项目类型;客户端 + Worker 采用统一模式语言 |
| 构建 | Vite 8 | 与 Start 相同 |
| 运行时 | Bun(开发/安装) | 快速;也支持 npm/pnpm/yarn |
## 运行
```sh
bun install
bun run dev # http://localhost:3000 (或下一个可用端口)
```
其他实用脚本:
```sh
bun run build # 生产构建
bun run preview # 预览生产构建
bun run typecheck # tsc --noEmit
bun run test:e2e # Playwright 端到端测试(chromium)
```
## 部署
仓库部署到 **Cloudflare Workers**:一个 Worker 提供静态 SPA *和* 路由 `/api/nodes` + `/api/kv` 同步 API 到 **用户专属 Durable Object**,背后是 **Better Auth** 账户。配置在 `wrangler.jsonc` 中。完整设计:[同步设计](docs/adr/0008-sync-via-a-per-user-durable-object.md)。
```sh
# 本地开发(两个终端):Vite HMR + 本地 Worker(DO + D1)代理 /api
cp .dev.vars.example .dev.vars # 一次:添加 BETTER_AUTH_SECRET(openssl rand -base64 32)
bun run db:migrate:local # 一次:应用本地 D1 模式(认证表 + DO 导入源)
bun run dev:api # wrangler dev(Worker + DO + 本地 D1)在 :8787
bun run dev # vite dev(代理 /api -> :8787)
# 或类似生产环境的单服务器预览
bun run cf:dev # 构建 + wrangler dev
# 部署
wrangler secret put BETTER_AUTH_SECRET # 一次:身份验证签名密钥
bun run db:migrate:remote # 首次部署前
bun run deploy # 构建 + wrangler 部署
```
`build:cf` 将 TanStack Start 外壳( `_shell.html`)复制到 `index.html`,以便根路径和客户端路由(例如 `/<nodeId>` 缩放视图)通过 SPA 回退解析。
**认证。** 身份验证为 **Better Auth**(邮件 + 密码自助注册),D1 中存储会话。静态外壳是公开的,因此登录屏幕可以加载;只有 `/api/nodes` + `/api/kv` 需要会话。在生产环境和 `.dev.vars` 本地环境中设置 `BETTER_AUTH_SECRET`(`wrangler secret put`);如果没有它,Worker 将关闭。要将预认证大纲(常量 `'default'` DO)带入您的真实账户,请在注册后将 `OWNER_USER_ID` 机密设置为您的 `user.id`。详见 [身份验证网关](docs/adr/0011-the-auth-gate.md)。
## 工作原理
### 数据模型
每个项目符号都是单一 TanStack DB 集合中的一行。大纲树在读取时在内存中重建。
```
Node {
id, parentId, prevSiblingId, // 树形结构 + 兄弟顺序
text, isTask, completed, collapsed, // 内容 + UI 状态
bookmarkedAt, // null,或固定时的毫秒数(也是书签排序键)
createdAt, updatedAt
}
```
兄弟顺序通过 `prevSiblingId` 实现链表(Workflowy/Notion 方法)。在两个项目符号之间插入节点是 O(1) 且无需重新编号。重新排序是重新链接指针。
详见 `src/data/tree.ts` 获取索引构建器,`src/data/mutations.ts` 获取结构操作 — 插入、缩进/取消缩进、融合的 `moveNode`(拖动重新排序 + 重新父级)、向上/向下移动、删除 — 加字段设置(文本、任务、完成、折叠、书签)。每个都保留链表不变性。
### 为什么是扁平结构而非嵌套结构
扁平的行列表与同步后端干净地映射。嵌套 JSON 将强制在每个按键时进行深度合并。扁平行保持移动廉价,并使每个后端移动(localStorage → D1 → 用户专属 Durable Object)成为 `nodes` 表的交换,而无需重写。
### 持久化
`nodesCollection`(`src/data/collection.ts`)是 TanStack DB **查询集合**:`queryFn` 从 `/api/nodes` 获取完整节点集,突变处理程序通过同一 Worker 发送 POST/PATCH/DELETE 请求,**将每个请求路由到调用者的 Durable Object**,并在附带的 SQLite 中读取/写入 `nodes` 表。我们直接突变(`collection.insert / update / delete`);写入在本地乐观并在服务端持久化,在选项卡聚焦时在设备间协调。详见 [同步设计](docs/adr/0008-sync-via-a-per-user-durable-object.md)。
插件 **侧集合**(标签颜色、日索引)以相同的方式同步,通过通用 `/api/kv` 存储(同一 DO 中的一个 `kv` 表,按集合命名空间)——因此自定义标签颜色或日记也跨设备同步。详见 [同步设计](docs/adr/0008-sync-via-a-per-user-durable-object.md)。
### 插件
编辑器是一个通过 **插件** 扩展的小型核心,编译到捆绑包中(内部注册表,非运行时加载)。`code`、`links`、`tags` 和 `todos` 都是在同一公共 API 上构建的插件,因此核心不携带特定于功能的代码分支。插件针对一组固定的 **缝隙** 注册 — 内联令牌、委托点击、`/` 命令、键映射、行插槽、视图转换、自动完成菜单、粘贴/自动格式化和侧集合。添加功能是在 `src/plugins/<name>/` 下新建一个文件夹,并在 `src/plugins/index.ts` 中添加一行。详见 [插件架构](docs/adr/0001-plugin-architecture.md)。
## 同步:现状
集合接口是与后端无关的 — 这就是将后端从(localStorage → D1 → 用户专属 Durable Object)更改只影响 `collection.ts` 和 Worker,而不影响任何组件和树逻辑的原因。
今天,**节点实时同步** 通过用户专属的 WebSocket(`/api/sync`):乐观写入仍然 POST/PATCH/DELETE `/api/nodes`,而 DO 会将更改广播到每个连接的选项卡/设备。**侧集合**(标签颜色、日索引)仍然在选项卡聚焦时协调(`refetchOnWindowFocus`)。尚未构建:
- **分享** — 将节点 + 子树与另一个用户分享(未来的“安装”指针;详见 [同步设计](docs/adr/0008-sync-via-a-per-user-durable-object.md)).
返回所有者的预 DO 大纲通过 **服务端** 携带:Worker 在第一次 `/api/sync` 连接时(`ensureSeeded`)将任何预 DO D1 行的非破坏性副本复制到所有者的 Durable Object 中。没有客户端 `localStorage` 迁移 — localStorage 按浏览器范围划分,但帐户按用户划分,因此导入它会将一个浏览器的剩余大纲泄露到在那里注册的所有新帐户中。
详见 [同步设计](docs/adr/0008-sync-via-a-per-user-durable-object.md) 获取设计和被拒绝的替代方案(包括为什么使用 Durable Object 而不是 D1-direct 或 ElectricSQL)。
## 代理(MCP)
大纲也可通过 [模型上下文协议](https://modelcontextprotocol.io) 由 AI 代理访问:指向一个 MCP 客户端到 `https://<your-deployment>/mcp`,它会经历标准的 OAuth 流程(使用您的正常帐户登录;客户端注册自身)。代理获得读取工具(`get_outline`、`search_nodes`)和写入工具(`add_node`、`update_node`、`delete_node`、`move_nodes`、`add_to_today`、`mirror_node`、`mirror_to_today`);每个写入都通过与编辑器相同的原子用户专属 Durable Object 路径,因此打开的选项卡会实时看到代理编辑。设计 + 被拒绝的替代方案:[代理原生 MCP 服务器](docs/adr/0026-agent-native-mcp-server.md)。
## 项目布局
```
src/
routes/
__root.tsx # HTML 外壳、全局 CSS、应用范围的提供者
index.tsx # 顶级大纲(首页)
$nodeId.tsx # 缩放至单个项目符号的大纲
lib/
auth-client.ts # Better Auth 浏览器客户端(useSession / signIn / signUp / signOut)
utils.ts # cn() 和小辅助函数
components/
auth-screen.tsx # 登录/注册屏幕(由根 AuthGate 显示,当退出时)
sign-out-button.tsx # 头部注销控件
OutlineEditor.tsx # 读取树、焦点 + 命令调度、缩放视图
OutlineNode.tsx # 单个项目符号 + 其子树( memoized,每个节点的存储订阅)
inline-code.ts # contentEditable 装饰/插入符号引擎(源偏移感知)
menu-engine.tsx # 通用插入符号自动完成引擎
slash-menu.tsx # `/` 命令面板
node-switcher.tsx # Cmd+K 快速切换器
move-dialog.tsx # `/move` 目标选择器
bookmarks.tsx # 头部星号 + 书签浏览
use-drag-reorder.ts # 项目符号圆点拖动(重新排序 + 重新父级)
Header.tsx, paste.ts, flash-node.ts, *-provider.tsx, *-toggle.tsx, ui/
data/
schema.ts # Effect Schema,Node 类型
collection.ts # TanStack DB 查询集合,基于 Worker(/api/nodes)
api.ts # /api/nodes 的 REST 客户端
kv-api.ts # 通用 /api/kv 侧集合存储的 REST 客户端
query-client.ts # 共享 TanStack 查询客户端(焦点重新获取 = 同步)
tree.ts # 扁平列表 -> TreeIndex,轨迹 / id / 时间帮助函数
tree-store.ts # 节点订阅(useNode / useVisibleChildIds)
mutations.ts # 插入 / 移动 / 删除 / 字段设置
history.ts # 撤销/重做捕获
tags.ts, tag-colors.ts, links.ts # 纯解析 + 标签颜色侧集合(通过 /api/kv 同步)
seed.ts # 首次运行引导:在大纲为空时播种欢迎项目符号
useTree.ts # useLiveQuery 钩子
plugins/ # 编辑器的插件层(详见 docs/adr/0001-plugin-architecture.md)
index.ts # 有序数组:[code, links, tags, todos, daily]
types.ts # 类型化的缝隙合约(definePlugin)
registry.ts # 组合每个插件的注册信息
code/ links/ tags/ todos/ daily/ # 一个文件夹/插件
router.tsx
styles.css
worker/ # Cloudflare Worker:提供 SPA + 路由 /api/nodes + /api/kv 到用户专属 DO
index.ts # 会话网关 + resolveUserId + 路由 /api 到用户专属 DO
auth.ts # createAuth(env):Better Auth(邮件 + 密码 + MCP OAuth 提供者),D1 中的会话
outline-do.ts # 用户大纲 DO:用户专属 SQLite(nodes + kv),大纲存储
mcp.ts # MCP 端点:/mcp 上的无状态 JSON-RPC
mcp-tools.ts # MCP 工具注册表(Effect 架构输入 + 用户专属 DO 上的处理程序)
outline-ops.ts # 纯服务端大纲规划器(快照 -> 原子更改操作批次)
migrations/ # D1 SQL 迁移(0001 nodes, 0002 kv = DO 导入源;0003 Better Auth;0004 OAuth/MCP)
wrangler.jsonc # Worker + 资产 + Durable Object + D1 绑定(+ nodejs_compat)
docs/adr/ # 每个负载决策都有一个 ADR(git 日志中有历史)
vite.config.ts # SPA 模式 + /api 开发代理
```
## 贡献
设置、本地开发循环、预 PR 检查矩阵和存储库约定都位于
[`CONTRIBUTING.md`](./CONTRIBUTING.md)。代理接口规则位于
[`AGENTS.md`](./AGENTS.md)。
## 许可
Copyright © FAITH TOOLS SOFTWARE SOLUTIONS, LLC. 在 [O'Saasy 许可](./LICENSE) 下发布。源代码可用于学习、修改和自我托管;提供竞争托管的 SaaS 产品保留给版权持有人。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器