Files
FootPrint/sync-server/README.md
T
root 8cdf8b44fa docs: refresh public docs for current codebase, add SECURITY.md
- README: real counts (44 commands, 61 integration asserts, demo=25 records
  + 4 semesters + 7 attachments), add resume/assessment module features,
  env vars incl. LSKY, doc navigation table, done-roadmap items checked
- docs/api.md: /auth/logout, admin users/demo-rebuild/sync-lsky routes,
  attachment thumb/download channels, profile_upsert top-key merge
  semantics, full footprint_list query reference, 44-command table
- sync-server/README: replace stale ADMIN_TOKEN/X-Admin-Token admin section
  (actual is_admin Bearer model), add go-live checklist, backup note for WAL
- CHANGELOG: add Unreleased section (resume/assessment modules, security
  fixes, perf tuning)
- CONTRIBUTING: 61 asserts, security-sensitive-change guidance, perf baseline
  table, security issue routing
- docs/SECURITY.md: new - report channel, threat model table, hardening
  summary, known tradeoffs
- LICENSE: ensure MIT file matches README badge
2026-10-17 22:27:56 +08:00

94 lines
5.1 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 游标增量拉取;每个用户一个独立 SQLite 档案库。
## 部署(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 库 + 附件),备份 = 复制该目录(WAL 模式建议连同 `-wal`/`-shm` 一起拷,或先 `wal_checkpoint(TRUNCATE)`)。
### 上线检查清单
- [ ] `INVITE_CODE` 改掉示例默认值 `please-change-me`(或留空改用管理页动态码)
- [ ] 第一个真实账号注册完成后 `REGISTER_ENABLED=false` 再 `docker compose up -d`
- [ ] `MAX_USERS` 按需限额(0 = 不限)
- [ ] `curl https://你的域名/health` 返回 `{"ok":true,...}`
- [ ] `./data/` 已纳入备份计划
## 多用户
服务端天然按账号隔离数据(每用户独立 `users/<uid>.db` 档案库,附件按用户子目录隔离),无需分库:
- 邀请码:`INVITE_CODE` 设置后,注册请求必须携带 `invite_code` 字段——把邀请码发给你信任的人即可;动态码由管理员在「管理」页生成(支持备注/启停/删除/批量)
- 名额:`MAX_USERS` 限制用户总数(0 = 不限),防滥用
- 管理:首位真实注册账号自动成为管理员(内置 demo 账号不占席位且永不为管理员);管理员登录后「管理」页可查看全部用户(设备数/记录数/附件占用)、删除用户(级联清理其图床文件/档案库/附件/会话)、重建演示账号
- 客户端:各用户安装桌面应用或 PWA,登录自己的账号即得到独立档案;同一台电脑可切换多个账号(本地档案按账号隔离)
- 数据安全:账号间完全隔离;管理员也只能看到元数据(用户名/设备数/存储占用),看不到档案内容
## 安全
- 必须经 HTTPS 访问(Caddy 自动证书);裸 HTTP 暴露公网不可接受
- 口令 scrypt 散列 + `timingSafeEqual` 校验;Bearer Token 365 天有效期,支持服务端吊销(`POST /auth/logout`)
- 登录限速:同 IP + 同用户名连续失败 5 次冷却 10 分钟
- 用户档案库仅用参数化 SQL;附件以 SHA-256 内容寻址命名(无路径可穿越)、哈希声明校验、100MB 单文件上限
- 详见 [`../docs/SECURITY.md`](../docs/SECURITY.md)
## API
完整参考见 [`../docs/api.md`](../docs/api.md)。同步面速览:
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /health | 健康检查(Docker healthcheck 使用) |
| POST | /auth/register | 注册 {username, password, invite_code, device_name},返回 {token, device_id} |
| POST | /auth/login | 登录,同上;同名设备复用 device_id |
| POST | /auth/logout | 吊销当前 Bearer Token |
| GET | /auth/me | 当前用户信息 |
| POST | /sync/push | 推送变更 {changes:[{table,row_uuid,op,hlc,data}]},返回 {accepted, stale, invalid} |
| GET | /sync/pull?cursor=N | 增量拉取,返回 {changes, cursor, has_more} |
| POST | /api/footprint_list 等 | 业务命令层 `POST /api/<command>`(44 个命令,按用户隔离) |
| POST | /api/attachment_download | 附件落盘下载(Content-Disposition 带原始文件名) |
鉴权:`Authorization: Bearer <token>`(除 /health /auth/register /auth/login 外全部需要)。
### 同步语义
- 服务端不解释业务字段,data 为不透明 JSON;业务表间引用由客户端以 uuid 表达
- 冲突:按 HLC(毫秒:计数:设备)三元组逐级比较,新者胜;旧推送计入 stale 并丢弃
- current 表存每行最新态,changes 表保留完整历史(seq 全局单调,即拉取游标)
- 附件按 (user, sha256) 去重,同一佐证多端引用仅存一份
## 目录
src/index.mjs HTTP 路由(静态/认证/管理/同步/命令层)
src/db.mjs Service 主库 schema(users/devices/tokens/invites)
src/auth.mjs 注册/登录/token/登出(scrypt + 限速)
src/sync.mjs push(LWW)/ pull(seq 游标)
src/app-commands.mjs 桥接共用命令层(app/server/db.mjs)
src/attachments.mjs 附件内容寻址存储
## 相关文件
- `docker-compose.caddy.yml`:与既有 Caddy 容器网络配合(推荐)
- `docker-compose.yml`:独立部署(本机回环端口)
- `Caddyfile.snippet`:Caddyfile 增量片段