Deeer
03Account & Sync运行中

StuMate Cloud

给 StuMate 桌面端配套的账号与同步服务。桌面端自己一直是本地优先的, 这个后端只补上「换一台电脑还能接着用」:账号、设备、GitHub 绑定, 以及基于 revision 游标的增量同步。

Year
2026
Form
REST / JSON
Stack
Next.js · SQLite
Auth
Bearer + refresh
01Decisions / 取舍

三个必须先想清楚的问题

设计与实现

01

本地优先,云端只做补充

桌面端自己的 SQLite 永远是权威数据源。云端只负责「换一台电脑还能接着用」,所以任何一次同步失败都不该影响本地使用 —— 断网时照常记课表、写便签。

02

游标增量,而不是全量覆盖

服务端维护一条 revision 流水,客户端存自己的游标。pull 只回 revision 大于游标的部分,hasMore 为真就立刻接着拉;不是首端时会带 replaceLocal 让本地清空重拉。

03

设备是一等公民

每个 access token 都绑定一个 deviceId。设置页能列出所有登录设备并单独解绑;改密以后可以按设备踢人,不用把所有人一起登出。

02Sync / 同步模型

一条流水,一个游标

服务端维护 revision 流水,客户端只存一个数字。比大小就知道该不该拉、 拉多少 —— 不需要维护「谁同步到哪了」这种两边都会写坏的状态。

  • cursor本次实际消费到的位置,下次原样传回来
  • hasMore为真就立刻接着拉,别等下一轮定时
  • replaceLocal不是首端:本地清空后全量重拉
  • countsclasses / notes / deleted 三个计数

GET /api/stumate/v1/sync/status

{
  "cursor": 1284,
  "is_initial_device": false,
  "counts": {
    "classes": 26,
    "notes": 41,
    "deleted": 3
  }
}

游标校验只收非负整数:`parseInt` 会把 `12abc` 悄悄读成 12, 也会让 `-5` 从未来往回拉。宁可返回 400,也不给客户端一个错游标。

03API / 接口

/api/stumate/v1 下面有什么

REST · Bearer

Auth

  • POST /auth/register邀请码注册
  • POST /auth/login登录,发 access + refresh
  • POST /auth/refresh用 refresh 换新 access
  • POST /auth/logout注销当前设备
  • POST /auth/password修改密码
  • POST /auth/password/set设置密码(OAuth 用户首次)
  • POST /auth/password/reset-with-code验证码重置
  • GET /auth/invite/check邀请码可用性

Me & Devices

  • GET /me当前账号
  • GET /me/devices登录设备列表
  • DELETE /me/devices/:id解绑指定设备

OAuth

  • POST /oauth/:provider/start发起绑定,拿授权地址
  • GET /oauth/:provider/callback浏览器回调
  • GET /oauth/:provider/poll桌面端轮询绑定结果
  • POST /oauth/:provider/bind完成绑定

Sync

  • GET /sync/statuscursor / is_initial_device / counts
  • GET /sync/pull?cursor=N增量拉取,单次上限 500
  • POST /sync/push推送本地变更

Runtime

跟本站同一个 Next 进程

Storage

独立 SQLite(stumate.db)

Health

/api/stumate/v1/health

客户端在 StuMate 桌面端的设置页里登录即可。