feat/self-hosted-sync
- 新增 Node 服务端(Hono + Hocuspocus + node:sqlite),数据保存在服务器 - 基于 Yjs 的多端实时同步,本机 IndexedDB 离线缓存,撤销只针对本机操作 - 空间(标签)有独立地址,增删改通过接口同步到所有设备 - 口令登录(签名 Cookie 会话、登录限流、同源校验) - 图片上传到服务器,过大照片上传前自动压缩 - 历史版本(自动/手动保存、一键恢复)、跨空间搜索、在线设备 - 随机油画加载动画(Painting Loaders,本地收录 p5 / p5.brush) - 选中样式与拖拽性能优化:拖动结束后才同步位置 - Docker / docker-compose 部署,README 与 CLAUDE.md 更新
无界笺 Boundless
一张可以无限延伸的灵感平面,自部署在自己的服务器上。所有内容保存在服务器里,手机、平板、电脑打开的都是同一张画布;在一台设备上修改,其他打开着同一空间的设备会立刻看到变化。
功能
- 无限画布:平移、缩放、小地图、框选、对齐与均分
- 文字便笺与图片卡片:创建、编辑、移动、缩放、复制、换色、连线
- 多个空间(标签),每个空间有独立的地址
/s/<空间 id> - 多端实时同步:基于 Yjs CRDT,多台设备同时编辑也不会互相覆盖
- 断网可用:离线时的修改保存在本机,联网后自动同步
- 撤销只针对本机:不会把其他设备的修改一起撤掉
- 历史版本:编辑时每 10 分钟自动存一个版本,也可以手动保存,一键恢复
- 全局搜索:搜索当前空间并跳转,同时列出其他空间里的匹配卡片
- 在线设备:查看哪些设备在线、各自打开的是哪个空间
- 口令登录:单用户,修改口令后所有设备自动退出
- 图片上传到服务器;过大的照片会在上传前自动压缩
- 随机油画加载动画(见下方致谢)
技术栈
- 前端: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+ 或 24.12+,推荐 Node.js 24 LTS。
pnpm install
cp .env.example .env # 可选;不设置时开发口令为 boundless
pnpm dev # 同时启动服务端(3000)与 Vite(5173)
浏览器打开 http://localhost:5173。服务端数据默认存放在 ./data/。
检查项目
pnpm build # 类型检查 + 构建
pnpm test:unit -- --run # 单元测试
pnpm exec playwright install chromium # 首次运行 e2e 前
pnpm exec playwright test --project=chromium # 端到端测试(会自动构建并启动服务端)
pnpm lint
部署(Docker)
echo "BOUNDLESS_PASSWORD=换成你的口令" > .env
docker compose up -d --build
服务监听 127.0.0.1:3000,数据保存在 ./data/(SQLite 数据库、图片和会话密钥)。备份整个 data/ 目录即可完整备份。
前面需要一个 HTTPS 反向代理,并且要支持 WebSocket。Caddy 最简单(自动申请证书,并会自动转发 WebSocket):
board.example.com {
reverse_proxy 127.0.0.1:3000
}
Nginx 需要显式转发 WebSocket 和 Host:
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(作者 Sasha),12 幅画作的绘制代码原样收录在 public/painterly/,基于 p5.js(LGPL-2.1)与 p5.brush(MIT)。
Description
Languages
Vue
38.9%
TypeScript
32.3%
CSS
28.3%
HTML
0.5%