自部署多端同步:服务端、实时协作、口令登录与油画加载动画

- 新增 Node 服务端(Hono + Hocuspocus + node:sqlite),数据保存在服务器
- 基于 Yjs 的多端实时同步,本机 IndexedDB 离线缓存,撤销只针对本机操作
- 空间(标签)有独立地址,增删改通过接口同步到所有设备
- 口令登录(签名 Cookie 会话、登录限流、同源校验)
- 图片上传到服务器,过大照片上传前自动压缩
- 历史版本(自动/手动保存、一键恢复)、跨空间搜索、在线设备
- 随机油画加载动画(Painting Loaders,本地收录 p5 / p5.brush)
- 选中样式与拖拽性能优化:拖动结束后才同步位置
- Docker / docker-compose 部署,README 与 CLAUDE.md 更新
This commit is contained in:
吴璨
2026-10-21 18:09:03 +08:00
parent c36123eb82
commit fad9760265
64 changed files with 6656 additions and 1103 deletions
+76 -25
View File
@@ -1,46 +1,97 @@
# 无界笺 Boundless
一张可以无限延伸的本地灵感平面。你可以在画布上自由放置文字与图片、连接相关想法,并使用不同空间分开生活中的主题。
一张可以无限延伸的灵感平面,自部署在自己的服务器上。所有内容保存在服务器里,手机、平板、电脑打开的都是同一张画布;在一台设备上修改,其他打开着同一空间的设备会立刻看到变化。
## 已实现
## 功能
- 无限画布平移、缩放、小地图和框选
- 文字便笺的创建、编辑、移动、缩放、复制和换色
- 图片选择、拖入与剪贴板粘贴
- 卡片之间的自由连线
- 多空间创建和切换
- 当前空间搜索
- IndexedDB 自动本地保存
- JSON 完整备份与恢复
- 响应式侧边栏
- 无限画布:平移、缩放、小地图、框选、对齐与均分
- 文字便笺与图片卡片:创建、编辑、移动、缩放、复制、换色、连线
- 多个空间(标签),每个空间有独立的地址 `/s/<空间 id>`
- **多端实时同步**:基于 Yjs CRDT,多台设备同时编辑也不会互相覆盖
- **断网可用**:离线时的修改保存在本机,联网后自动同步
- **撤销只针对本机**:不会把其他设备的修改一起撤掉
- **历史版本**:编辑时每 10 分钟自动存一个版本,也可以手动保存,一键恢复
- **全局搜索**:搜索当前空间并跳转,同时列出其他空间里的匹配卡片
- 在线设备:查看哪些设备在线、各自打开的是哪个空间
- 口令登录:单用户,修改口令后所有设备自动退出
- 图片上传到服务器;过大的照片会在上传前自动压缩
- 随机油画加载动画(见下方致谢)
## 技术栈
- Vue 3 + TypeScript 6
- Vite 8(Rolldown)
- Vue Flow
- Pinia + Dexie / IndexedDB
- Tailwind CSS 4
- Vitest + Playwright
- 前端:Vue 3 + TypeScript、Vite 8、Vue Flow、Pinia、Tailwind CSS 4
- 同步:Yjs、Hocuspocus(WebSocket)、y-indexeddb(本机离线缓存)
- 服务端:Node.js(直接运行 TypeScript)、Hono、node:sqlite
- 测试:Vitest、Playwright
## 本地运行
## 本地开发
需要 Node.js 22.18+ 或 Node.js 24.12+,推荐使用 Node.js 24 LTS。
需要 Node.js 22.18+ 或 24.12+,推荐 Node.js 24 LTS。
```sh
pnpm install
pnpm dev
cp .env.example .env # 可选;不设置时开发口令为 boundless
pnpm dev # 同时启动服务端(3000)与 Vite(5173)
```
浏览器打开终端显示的本地地址即可使用。
浏览器打开 <http://localhost:5173>。服务端数据默认存放在 `./data/`。
## 检查项目
```sh
pnpm build
pnpm test:unit -- --run
pnpm exec playwright test --project=chromium
pnpm build # 类型检查 + 构建
pnpm test:unit -- --run # 单元测试
pnpm exec playwright install chromium # 首次运行 e2e 前
pnpm exec playwright test --project=chromium # 端到端测试(会自动构建并启动服务端)
pnpm lint
```
所有记录默认只保存在当前浏览器的 IndexedDB 中。请定期使用左下角的“导出备份”保存一份 JSON 文件。
## 部署(Docker)
```sh
echo "BOUNDLESS_PASSWORD=换成你的口令" > .env
docker compose up -d --build
```
服务监听 `127.0.0.1:3000`,数据保存在 `./data/`(SQLite 数据库、图片和会话密钥)。**备份整个 `data/` 目录即可完整备份。**
前面需要一个 HTTPS 反向代理,并且要支持 WebSocket。Caddy 最简单(自动申请证书,并会自动转发 WebSocket):
```caddyfile
board.example.com {
reverse_proxy 127.0.0.1:3000
}
```
Nginx 需要显式转发 WebSocket 和 Host:
```nginx
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 1d;
client_max_body_size 25m;
}
```
### 环境变量
| 变量 | 说明 | 默认值 |
| -------------------- | ------------------------------------------- | ------------------- |
| `BOUNDLESS_PASSWORD` | 登录口令(生产环境必填) | 开发时为 `boundless` |
| `BOUNDLESS_SECRET` | 会话签名密钥 | 自动生成并存入数据目录 |
| `DATA_DIR` | 数据目录 | `./data` |
| `PORT` / `HOST` | 监听端口与地址 | `3000` / `0.0.0.0` |
| `SESSION_DAYS` | 登录有效天数 | `90` |
| `MAX_IMAGE_MB` | 单张图片大小上限 | `20` |
不用 Docker 时:`pnpm install && pnpm build-only && BOUNDLESS_PASSWORD=... pnpm start`。
## 致谢
加载动画来自 [Painting Loaders](https://painterly.design-tools.workers.dev)(作者 [Sasha](https://x.com/aleksksaa)),12 幅画作的绘制代码原样收录在 `public/painterly/`,基于 [p5.js](https://p5js.org)(LGPL-2.1)与 [p5.brush](https://github.com/acamposuribe/p5.brush)(MIT)。