覆盖注册 → 试用 → 宽限期 → 只读 → 锁定 → 续费激活全链路
| 阶段 | expires_at 设置 | 写操作 | 登录 | 前端表现 |
|---|---|---|---|---|
| normal | 未来时间(未过期) | ✅ 正常 | ✅ 正常 | 绿色状态,无横幅 |
| grace | 1–7 天前 | ✅ 正常 | ✅ 正常 | 橙色横幅 + 启动弹窗 |
| readonly | 7–15 天前 | 🚫 403 | ✅ 正常 | 红色横幅,写操作提示错误 |
| locked | 15+ 天前 | 🚫 403 | 🚫 拒绝 | 登录失败提示 |
# 在项目根目录执行
export PATH="/opt/homebrew/bin:$PATH"
cd backend
go run ./cmd/genkey
输出两段 base64:第一段是私钥(存 Bitwarden),第二段是公钥。
.env 中):
export LICENSE_ED25519_PRIVATE_KEY="<私钥 base64>" export LICENSE_ED25519_PUBLIC_KEY="<公钥 base64>"
SELECT id, shop_id, type, expires_at, is_active, max_devices FROM licenses ORDER BY id DESC LIMIT 1;记下
shop_id,后续所有 SQL 替换 1 为该值。
-- shop_id 替换为你的实际值 UPDATE licenses SET expires_at = DATE_SUB(NOW(), INTERVAL 3 DAY) WHERE shop_id = 1;
UPDATE licenses SET expires_at = DATE_SUB(NOW(), INTERVAL 10 DAY) WHERE shop_id = 1;
UPDATE licenses SET expires_at = DATE_SUB(NOW(), INTERVAL 20 DAY) WHERE shop_id = 1;
5.1 运营方:签发授权码
# shop 替换为实际 shop_id;days 为有效天数;devices 为最大设备数
export PATH="/opt/homebrew/bin:$PATH"
cd backend
go run ./cmd/issue \
-shop 1 \
-days 365 \
-type annual \
-devices 5
输出的 token 字符串即为授权码,复制备用。
5.2 用户:在应用内激活
-- 临时恢复到 grace 阶段(允许登录) UPDATE licenses SET expires_at = DATE_SUB(NOW(), INTERVAL 3 DAY) WHERE shop_id = 1;
-- 恢复为 30 天后到期(正常试用状态) UPDATE licenses SET expires_at = DATE_ADD(NOW(), INTERVAL 30 DAY) WHERE shop_id = 1;
LicenseExpiresAt 缓存在 JWT 里,不重登前端阶段判断不会更新(登录拦截除外,那个实时读 DB)shop_id 替换为你实际注册账号对应的值,通常第一个账号为 1LICENSE_ED25519_PRIVATE_KEY 环境变量,确保 shell 会话中已导出