Files
FootPrint/sync-server/README.md
T
root 42ca57abfd feat: 足迹 Footprints 个人留痕系统
桌面应用(Tauri+React+SQLite):时间线/记录/学年学科成绩梯度/统计/类型与字段模板/附件内容寻址/详情视图/PWA

同步服务端(sync-server):多用户+邀请码/LWW推拉/seq游标/附件去重/Docker部署

多端同步地基:uuid v7/HLC混合逻辑时钟/软删除墓碑/sync_oplog,Node与Rust双端一致并通过自动化测试
2026-10-16 13:53:15 +08:00

82 lines
4.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 增量片段