Files
FootPrint/sync-server
root d534cae0e1 feat(admin): delete user wipes all remote/local data (blobs + sqlite + changes), invite holder_gone mark
\u9080\u8bf7\u7801\u5df2\u7528\u4f46\u6301\u6709\u4eba\u88ab\u6ce8\u9500\u65f6\u7ba1\u7406\u9875\u5c55\u793a\u5df2\u9500\u6237\u5f82\u7ae0\u4e0e\u7b5b\u9009\u3002
2026-10-17 17:04:51 +08:00
..

Footprints 自建同步服务

个人留痕系统的多端同步服务端。零 npm 依赖(Node 内置 node:sqlite),SQLite 单文件存储, 专为单用户/小规模多设备设计。协议:行级 LWW(HLC 仲裁)+ seq 游标增量拉取。

部署(Docker)

方式一:已有 Caddy 容器网络(推荐,与你现有 gitea/halo 等部署同构)

# 1. 仓库上传到服务器(如 /opt/footprints),进入 sync-server 目录
# 2. 网络名已预设为 mynet(Caddy 共享网络,无需再改)
docker compose -f docker-compose.caddy.yml up -d --build

容器不映射宿主端口,Caddy 直接按服务名反代。Caddyfile 增加一块(与现有写法并列):

footpr.linyux.cn {
    reverse_proxy footprints-sync:8788
}

前置:为 footpr.linyux.cn 添加 A 记录指向服务器 IP,Caddy 自动签发证书;重载 Caddy(caddy reload 或重启容器)。

方式二:独立部署(无 Caddy 网络时)

docker compose up -d --build
# 默认只绑定 127.0.0.1:8788,交给宿主上的反代;需要直连时改为 "8788:8788"

数据全部落在 ./data/(SQLite 库 + 附件 Blob),备份 = 复制该目录。

  • 首次部署 REGISTER_ENABLED=true,注册自己的账号后改为 false 再 docker compose up -d 关闭注册
  • 验证:curl https://footpr.linyux.cn/health 应返回 {"ok":true,...}

多用户

不止一人使用时,服务端天然按账号隔离数据(变更/附件/设备均挂 user_id),无需分库:

  • 邀请码:INVITE_CODE 设置后,注册请求必须携带 invite_code 字段——把邀请码发给你信任的人即可
  • 名额:MAX_USERS 限制用户总数(0 = 不限),防滥用
  • 管理:设置 ADMIN_TOKEN 后,GET /admin/users(请求头 X-Admin-Token)可查看全部用户、设备数、记录数与附件占用
  • 客户端:各用户安装桌面应用或 PWA,登录自己的账号即得到独立档案;同一台电脑可切换多个账号(本地档案按账号隔离)
  • 数据安全:账号间完全隔离;管理员也只能看到元数据(用户名/设备数/存储占用),看不到档案内容

安全要点

  • 必须经 HTTPS 访问(Caddy 自动证书);裸 HTTP 暴露公网不可接受
  • 数据(SQLite + 附件 Blob)全在 ./data/,定期备份该目录即可
  • 服务端不解释业务字段;表间引用由客户端以 uuid 表达

API

方法 路径 说明
GET /health 健康检查(Docker healthcheck 使用)
POST /auth/register 注册 {username, password, device_name},返回 {token, device_id}
POST /auth/login 登录,同上;同名设备复用 device_id
POST /sync/push 推送变更 {changes:[{table,row_uuid,op,hlc,data}]},返回 {accepted, stale, invalid}
GET /sync/pull?cursor=N 增量拉取,返回 {changes, cursor, has_more}
POST /sync/attachment 上传附件 {sha256,size,mime,file_name,data_b64},返回 {dedup}
GET /sync/attachment/:sha256 下载附件(内容寻址,跨设备去重)
GET /sync/status 账号统计

鉴权:Authorization: Bearer <token>(/sync/* 全部需要)。

同步语义

  • 服务端不解释业务字段,data 为不透明 JSON;业务表间引用由客户端以 uuid 表达
  • 冲突:按 HLC(毫秒:计数:设备)三元组逐级比较,新者胜;旧推送计入 stale 并丢弃
  • current 表存每行最新态,changes 表保留完整历史(seq 全局单调,即拉取游标)
  • 附件按 (user, sha256) 去重,同一佐证多端引用仅存一份

目录

src/index.mjs         HTTP 路由
src/db.mjs            SQLite schema 与连接
src/auth.mjs          注册/登录/token(scrypt)
src/sync.mjs          push(LWW)/ pull(seq 游标)
src/attachments.mjs   附件内容寻址存储

相关文件

  • docker-compose.caddy.yml:与既有 Caddy 容器网络配合(推荐)
  • docker-compose.yml:独立部署(本机回环端口)
  • Caddyfile.snippet:Caddyfile 增量片段