feat: enforce practice access controls

This commit is contained in:
Codex
2026-06-28 23:23:02 +08:00
parent 3647c2bc2d
commit 6a7294224d
12 changed files with 1047 additions and 110 deletions

View File

@@ -152,6 +152,51 @@ tenant:<tenantId>:theme
| 个人中心 | `GET/PATCH /api/profile/me` |
| 销售分享 | `/api/referral/resolve``track-event``bind` |
## 练习访问控制契约
前端不要先拉完整题目列表再自行判断免费额度。用户点击顺序刷题、随机刷题、全真模拟时,统一调用 `POST /api/learning/practice-sessions`,后端会根据 `content_entries.accessRules``content_nodes.accessRules``question_collections.accessRules``practice_blueprints.accessRules` 和当前用户权益决定最终题目快照。
请求示例:
```json
{
"mode": "sequential",
"collectionId": "00000000-0000-0000-0000-000000000615",
"questionLimit": 50
}
```
响应关键字段:
```json
{
"item": {
"id": "...",
"mode": "sequential",
"questionIds": ["..."],
"questionCount": 25,
"accessMode": "free",
"consumedFreeQuota": 25,
"accessSnapshot": {
"grantedBy": "free_quota",
"requestedCount": 50,
"grantedCount": 25,
"truncated": true,
"dailyLimit": 25
}
}
}
```
前端处理规则:
- 以返回的 `questionIds` 为准渲染本次练习,不要自行追加题目。
- `accessSnapshot.truncated=true` 时,可提示“今日免费额度有限,已为你开放 N 题”并引导开通 SVIP。
- `PRACTICE_FREE_LIMIT_REACHED`:弹出会员购买/激活码兑换入口。
- `PRACTICE_SVIP_REQUIRED`:提示该内容需要对应地区/科目/题库 SVIP。
- `PRACTICE_SESSION_QUESTION_FORBIDDEN`:说明提交答案的题目不在本次 session 快照内,应清理本地异常进度并重新开始。
- 提交答案必须传 `practiceSessionId`;后端会拒绝不属于本人有效 session 的题目。
## 视频播放契约
题目视频分为 `free``svip``video_quota` 三种访问模式。列表接口只用于展示标题、封面、时长、访问模式和试看秒数;除免费公开视频外,列表和搜索接口不会返回可播放 URL。