106 lines
6.5 KiB
Markdown
106 lines
6.5 KiB
Markdown
# T-636 客户端订阅策略 django-admin 运营开关
|
|
|
|
## 背景
|
|
|
|
T-635 已经通过公开版本检查接口向新版 cmshopee 客户端发布启动订阅策略,
|
|
但策略只能通过修改 `.env` 后重启 Web / Generate 服务变更。该方式不适合日常
|
|
运营,也无法在 django-admin 中留下明确的变更原因和操作者。
|
|
|
|
客户端策略和 `CMSHOPEE_SUBSCRIPTION_MODE` 的服务端授权仍是两件事:前者只
|
|
决定新版客户端是否检查 / 展示会员门禁,后者才决定产品专属生成接口是否按真实
|
|
权益拦截。本任务不得混淆或合并这两套开关。
|
|
|
|
## 目标
|
|
|
|
1. 让超级管理员在 django-admin 中用单一枚举切换 `off`、`observe`、`enforce`。
|
|
2. 每次变更必须留存原因、操作者、前后值和时间。
|
|
3. 公开版本检查接口在下一次请求立即发布后台策略,无需重启服务。
|
|
4. 未配置后台策略时完全保留 T-635 `.env` 行为,保证上线不改变当前客户端。
|
|
|
|
## 实施范围
|
|
|
|
### 数据模型与策略来源
|
|
|
|
- 新增全局单例 `ClientSubscriptionPolicy`,仅保存一个固定主键记录;字段至少有
|
|
`mode`、`updated_by`、`created_at`、`updated_at`。
|
|
- 模式只能是 `off|observe|enforce`,输出继续复用 T-635 的统一映射:
|
|
`off -> false/false`、`observe -> true/false`、`enforce -> true/true`。
|
|
- 新增不可修改的策略审计记录,保存 `previous_mode`、`mode`、必填 `reason`、
|
|
`changed_by`、`changed_at`。审计不保存 API Key、用户权益、点数、订单、prompt
|
|
或图片。
|
|
- 迁移只创建空表,不写预置策略记录。策略解析顺序固定为:数据库单例存在时优先
|
|
使用其 `mode + updated_at`;记录不存在时回退
|
|
`CMSHOPEE_CLIENT_SUBSCRIPTION_POLICY` 与
|
|
`CMSHOPEE_CLIENT_SUBSCRIPTION_POLICY_UPDATED_AT`。
|
|
- 公开接口每次请求读取单例,不使用进程内缓存;因此 admin 保存成功后下一次请求
|
|
即生效。数据库不可用仍按既有 Django 请求失败语义处理,不得静默发布错误策略。
|
|
|
|
### django-admin
|
|
|
|
- 日常导航只增加“客户端订阅策略”一个入口;审计仅作为该详情页的只读 inline,
|
|
不单独出现在导航。
|
|
- 仅超级管理员可新增或编辑;不允许删除。首次创建后禁止新增第二条记录。
|
|
- 表单除 `mode` 外必须填写“变更原因”。服务层负责事务内写单例与审计,禁止通过
|
|
admin 直接 `save()` 绕过审计。
|
|
- 展示当前 `CMSHOPEE_SUBSCRIPTION_MODE` 为只读信息,明确它是服务端授权模式;
|
|
本页不得修改该环境变量,也不得修改权益、套餐、席位、凭证、订单、钱包或点数。
|
|
- 相同模式不应制造伪变更审计;要求运营选择不同模式后再保存。
|
|
|
|
### API 与兼容
|
|
|
|
- `GET /api/v1/client/releases/latest?platform=windows` 顶层 `client_policy` 结构、
|
|
`policy_version=1`、字段类型和 `Cache-Control: no-store` 保持 T-635 合约。
|
|
- 有发布、`release:null` 和无下载地址路径均使用同一策略来源;既有
|
|
`force_update`、`size_bytes` 等发布字段不回归。
|
|
- 此接口仍匿名只读、无账号上下文,不读取 `SoftwareEntitlement`、套餐、点数、
|
|
订单、API Key 或生成模型;新增的仅是全局策略配置读取。
|
|
- 不修改 `CMSHOPEE_SUBSCRIPTION_MODE`,不改变通用或专属生成接口、计费预扣 /
|
|
确认 / 退款、支付回调、软件订单、异步图片任务或旧客户端行为。
|
|
|
|
## 部署与回滚
|
|
|
|
1. 备份生产应用和数据库,发布代码并执行 `migrate`;迁移不会创建策略记录。
|
|
2. 首次部署后确认 `.env` 兜底策略仍为 `off`,公开接口保持
|
|
`subscription_check_enabled=false`、`subscription_enforcement_enabled=false`。
|
|
3. 超级管理员可创建单例并按 `off -> observe -> enforce` 灰度;每次保存立即以新的
|
|
`updated_at` 发布,无需重启。
|
|
4. 需要紧急取消客户端门禁时,在后台将模式改为 `off`;若后台记录尚未创建,继续
|
|
使用 `.env` 兜底。不要把此操作误认为取消服务端授权。
|
|
5. 若需恢复到纯 `.env` 来源,必须先在维护窗口以受控数据操作移除单例记录;本任务
|
|
的 admin 不提供删除入口,避免误删和审计丢失。
|
|
|
|
## 验收条件
|
|
|
|
1. 无后台记录时三种合法 `.env` 配置保持 T-635 映射与启动校验。
|
|
2. 后台记录存在时优先于 `.env`;保存 `observe` / `enforce` 后下一次公开请求立即
|
|
返回正确双布尔值与稳定、带时区的 `updated_at`。
|
|
3. 模型层和后台均不能创建第二条记录,后台不能删除;非超级管理员不能新增或编辑。
|
|
4. 每次有效变更都写一条只读审计,包含前后模式、非空原因、操作者和时间;相同模式
|
|
被表单拒绝,不写伪审计。
|
|
5. 审计不出现在 admin 日常导航,策略页可只读查看历史;服务端授权模式只读展示。
|
|
6. 版本检查接口继续匿名、`Cache-Control: no-store`,且发布字段和无发布路径不回归;
|
|
不查询或泄露用户、权益、套餐、点数、订单、API Key 或密钥。
|
|
7. 同步更新 `docs/api.md`、`docs/env.md`、`docs/deployment.md`、
|
|
`docs/04-architecture.md`、`docs/current-state.md`、任务状态、`progress.md` 和
|
|
Obsidian 客户端契约。
|
|
8. `makemigrations --check --dry-run`、`migrate`、`check`、目标 API / licensing /
|
|
admin 测试、`init.ps1` 与 `git diff --check` 通过。
|
|
|
|
## 状态
|
|
|
|
DOING。代码、迁移和目标回归已完成,待标准验证、提交和生产部署。
|
|
|
|
## 实施结果(待部署)
|
|
|
|
- 新增 `ClientSubscriptionPolicy` 与 `ClientSubscriptionPolicyAudit`,迁移
|
|
`licensing.0006_client_subscription_policy` 只建空表。策略固定主键为 `1`,并由
|
|
数据库 CHECK 约束拒绝第二个主键;没有预置记录,保留既有 `.env` 兜底。
|
|
- `get_published_client_subscription_policy()` 每次公开版本检查优先读取后台单例,
|
|
用其 `updated_at` 发布原有 `client_policy` 结构;未创建记录时继续调用 T-635
|
|
的环境配置校验。没有进程内缓存,后台保存后下一次请求立即生效。
|
|
- django-admin 新增“客户端订阅策略”入口:仅超级管理员可新增 / 编辑,不能删除;
|
|
表单强制填写原因,服务层在事务内写策略和只读审计。策略详情显示当前服务端订阅
|
|
模式,但不允许修改它;审计只作为 inline 展示,不增加导航噪音。
|
|
- 未改通用 / 专属生成、服务端订阅授权、用户权益、套餐、点数、支付、软件订单或
|
|
异步图片任务。
|