feat: add content asset security scanning

This commit is contained in:
Codex
2026-06-29 19:42:05 +08:00
parent d696fc38b0
commit ecd269b548
21 changed files with 936 additions and 75 deletions

View File

@@ -98,9 +98,10 @@
| 上传后对象校验 | 可联调 | `/api/tenant-content/assets/confirm-upload`;托管对象必须 verified 后才能发布/下载 |
| PDF/图片预览签名 | 可联调 | `/api/catalog/assets/preview``/api/tenant-content/assets/sign-preview`;使用 inline 短期签名,学生预览默认短 TTL |
| 托管资源 worker 复检 | 可联调 | `apps/worker --job assets` 定期复检 pending/verified 对象元数据;异常资源会标记 failed 并从 active 退回 draft写入审计和 `security_flags` |
| 内容资源安全扫描 | 可联调 | `content_assets.security_scan_status` + `content_asset_security_scan_events`;托管对象确认上传后进入 `pending/scanning`,内置 `metadata_rules` 通过后才可发布、下载、预览或视频播放;失败会下架并写审计 |
| 资源访问审计 | 可联调 | `content_asset_access_events` + `GET /api/tenant-content/assets/access-events`;记录上传签名/确认、学生下载/预览、后台下载/预览的 granted/denied、TTL、签名模式、IP 和 UA |
| CDN 访问边界 | 可联调 | `members/svip/private` 外部 CDN URL 默认拒绝,必须显式 `metadata.providerManagedAccess=true``cdnAccessMode=signed_by_provider`;视频绑定资源也复用该规则 |
| 深度防盗链/水印/杀毒 | 待补齐 | 商用上线前继续补动态水印、安全扫描、CDN 刷新和对象生命周期策略 |
| 深度防盗链/水印/杀毒 | 待补齐 | 商用上线前继续补真实 AV/内容安全 provider、动态水印、CDN 刷新和对象生命周期策略;内置 metadata 规则扫描已完成 |
## 订单、会员、营销

View File

@@ -28,7 +28,7 @@
| 知识手册 | 可联调 | 科目、章节、条目、Markdown 内容、嵌套 JSON/CSV/Excel 导入 | 富文本资源、版本管理、附件/PDF 关联 |
| 分数线 | 可联调 | 院校、专业、动态字段、记录、年份、趋势、后台维护、JSON/CSV/Excel 导入 | 复杂筛选、AI 择校上下文 |
| 视频解析 | 可联调 | 单题视频、批量查询、后台视频绑定、JSON/CSV/Excel 导入、会员播放权限、播放次数扣减、签名 URL 和播放日志 | 深度防盗链、动态水印、播放统计 |
| 资料下载 | 部分完成 | 资源台账、SVIP 权限校验、`local_dev`/阿里云 OSS/腾讯 COS/Supabase Storage 上传下载签名、上传确认、PDF/图片预览签名、assets worker 复检异常下架、题库导出 PDF/Word/每日一练 ZIP 可生成 `content_assets` 并走签名下载/预览 | CDN 防盗链、杀毒扫描、视频水印、资料前端操作体验 |
| 资料下载 | 部分完成 | 资源台账、SVIP 权限校验、`local_dev`/阿里云 OSS/腾讯 COS/Supabase Storage 上传下载签名、上传确认、PDF/图片预览签名、访问审计、assets worker 复检和内置安全扫描、题库导出 PDF/Word/每日一练 ZIP 可生成可信 `content_assets` 并走签名下载/预览 | CDN 防盗链、真实 AV/内容安全 provider、视频水印、资料前端操作体验 |
| 会员与订单 | 可联调 | 下单、订单详情/状态轮询、优惠券领取/抵扣、零元订单自动开通、手工确认权限保护、激活码预检查/兑换、微信支付、支付宝、微信/支付宝发起退款、微信/支付宝退款查询确认、微信/支付宝退款通知 webhook、支付/退款补偿 worker、权益发放、资金对账批次/明细/异常查询 API、对账差错工单和事件轨迹 | 微信/支付宝官方账单自动下载、财务复核报表和异常订单运营台 |
| 登录认证 | 可联调 | 短信 mock、阿里云/腾讯云短信 adapter、迁移期 session、Supabase Auth JWT、微信小程序登录、微信网页登录、QQ 登录、手机号绑定/换绑、OAuth 配置表 | 真实生产账号和回调域名联调 |
| 销售/代理/CRM | 可联调 | 邀请码、首绑保护、团队关系、销售统计、CRM 配置/队列、钉钉/飞书/企微 worker、分佣规则、成员分佣比例、订单/激活码归因、结算生成、审核和打款状态Taro 营销中心已接第一版操作台 | 小程序码真实生成、CRM 分配策略、结算导出、真实打款、凭证、财务复核和销售转化看板 |
@@ -76,7 +76,7 @@
### P0上云测试和前端主链路前必须处理
- 生产鉴权API 已支持 Supabase Auth JWT继续做真实云端 Auth/JWKS 回归、RLS 深测,并在生产关闭 `x-user-id``x-platform-admin-key` 兼容入口。
- 对象存储:上传/下载签名已接入阿里云 OSS、腾讯云 COS、Supabase Storage上传确认、PDF/图片预览签名、assets worker 复检和题库导出 PDF/Word/每日一练 ZIP worker 已完成,继续补视频播放防盗链、杀毒扫描和动态水印。
- 对象存储:上传/下载签名已接入阿里云 OSS、腾讯云 COS、Supabase Storage上传确认、PDF/图片预览签名、assets worker 复检、内置安全扫描和题库导出 PDF/Word/每日一练 ZIP worker 已完成,继续补视频播放防盗链、真实 AV/内容安全 provider 和动态水印。
- 真实数据 dry-run导出 PocketBase 用户、题库、单词、知识手册、分数线、订单、权益,先跑 `npm run pb:import:dry-run`,再跑迁移和校验报告。
- 生产环境配置:`.env.example``npm run readiness:production` / `npm run readiness:production:db` 已补;继续补数据库迁移流程、备份恢复、日志、告警和 API 容器部署说明。
- Taro scaffold`apps/taro` 地基已建立;学生端、租户后台、平台后台第一批 H5 页面已接真实 API学生端已接地区选择、错题/收藏复习、阅读理解/案例分析多小题作答、题目反馈、视频解析、练习/模考报告、收银台、订单详情和售后入口第一版,平台后台关键写操作第一版已接入,租户工作台已接权限驱动模块入口,租户学生运营页已接学生创建/更新、禁用/恢复、批量导入、批量分班、备注和跟进任务第一版,租户内容页已接公共题库采纳/同步、冲突查看、单条/批量采纳平台或保留本地、导入问题、字段模板预览/下载、上传/粘贴预览、字段别名覆盖、同步/异步导入、异步轮询和复检详情第一版,租户设置页已接角色模板创建/编辑/停用、成员绑定模板和权限可见性配置第一版,租户营销中心已接 CRM 配置/队列和分佣结算操作台第一版;下一步补公式图片混排、更细数据范围 UI、平台后台审计增强和小程序兼容验证。

View File

@@ -259,14 +259,14 @@ GET /api/tenant-admin/audit-logs
- 学生批量导入、批量分班、学生状态、备注和跟进任务都使用独立权限点;教师默认可为范围内学生写备注和跟进任务,但不能批量导入、禁用学生或放大可见班级。
- 销售/代理客资采用首绑保护:普通扫码/分享事件不会覆盖已有归属,只有具备 `referral:write` 的租户成员可手动强制补绑。
- CRM 当前完成配置、密钥入私密表、客资入队、队列查询和 `apps/worker` 消费worker 支持 generic webhook、钉钉、飞书、企业微信机器人消息体/签名、失败重试和日志。
- 内容资源当前完成台账、租户后台维护、学生端 SVIP 下载权限,以及 `local_dev`、阿里云 OSS、腾讯 COS、Supabase Storage 的上传/下载签名 provider上传确认assets worker 已支持对象元数据校验/复检。PDF 预览渲染、防盗链、水印和安全扫描仍需继续补。
- 内容资源当前完成台账、租户后台维护、学生端 SVIP 下载权限,以及 `local_dev`、阿里云 OSS、腾讯 COS、Supabase Storage 的上传/下载签名 provider上传确认、访问审计、assets worker 对象元数据校验/复检和内置 `metadata_rules` 安全扫描已完成。PDF 深度预览体验、防盗链、水印和真实 AV/内容安全 provider 仍需继续补。
- 题库内容导航当前以 `content_entries/content_nodes` 为主模型,可表达“入口 -> 多级分类 -> 院校/专业/学科/销售意向标记”;题目集合和练习方式由 `question_collections/practice_blueprints` 管理,练习 session 会保存当次题目 ID 快照。
- 练习访问控制由 `content_entries/content_nodes/question_collections/practice_blueprints``accessRules` 合并决定;普通用户消耗 `practice_daily_usage`,事件写入 `practice_access_events`SVIP/staff 不消耗免费额度。
- 批量导入当前支持题目、单词、知识手册、分数线、视频 JSON/CSV/Excel 预览、逐行 issue、job/item 台账、同步执行或 `executionMode=async` 异步执行、幂等跳过,并可落到新内容入口、分类节点、分数线表或题目视频绑定。旧单词模板的 `vocabulary_units_示例数据` / `vocabulary_示例数据`、知识手册的书籍/章节/小节/知识点嵌套结构都由后端规范化。导入后复检、模板下载和字段映射 API 已补齐,前端 UI 待接。
## 下一步
1. 完善内容导入和文件上传:字段映射 UI、真实数据 dry-run、PDF 预览渲染、防盗链、杀毒扫描和视频水印。
1. 完善内容导入和文件上传:字段映射 UI、真实数据 dry-run、PDF 预览渲染、防盗链、真实 AV/内容安全 provider 和视频水印。
2. 完成真实短信 provider 联调:阿里云/腾讯云,密钥放 `app_private.tenant_secrets` 或生产 Vault。
3. 完成真实 OAuth provider 联调微信网页、微信小程序、QQ确认回调域名、开放平台账号和旧 PocketBase 身份映射策略。
4. 补微信/支付宝官方账单自动下载、异常订单运营台和优惠券核销报表;支付/退款补偿、退款查询确认、退款通知、资金对账导入比对和差错工单主链路已完成。

View File

@@ -24,7 +24,7 @@
| 知识手册 | 基础完成 | 科目、章节、条目只读与后台维护、书籍/章节/小节/知识点嵌套 JSON 预览导入、内容导航绑定 | 富文本资源、版本管理、附件/PDF 关联、Excel/Markdown 批量解析 |
| 分数线 | 可联调 | 字段、院校、专业、记录、趋势、年份、JSON 批量导入 | 复杂动态筛选、AI 择校数据上下文 |
| 视频解析会员 | 可联调 | 题目视频、批量查询、后台绑定、视频 JSON 导入、SVIP 权限、播放次数扣减、签名 URL、播放日志 | 深度防盗链、动态水印、播放统计 |
| 资料下载/PDF | 可联调 | `content_assets` 资源台账、后台资源管理、OSS/COS/Supabase Storage 上传下载签名、上传确认、PDF/图片预览签名、学生端列表、SVIP 下载权限、assets worker 复检 | CDN 防盗链、杀毒扫描、资料前端管理页 |
| 资料下载/PDF | 可联调 | `content_assets` 资源台账、后台资源管理、OSS/COS/Supabase Storage 上传下载签名、上传确认、PDF/图片预览签名、学生端列表、SVIP 下载权限、assets worker 复检和内置安全扫描 | CDN 防盗链、真实 AV/内容安全 provider、资料前端管理页 |
| 营销中心 | 基础完成 | SVIP 套餐、激活码批次、激活码生成、优惠券、Banner/FAQ/公告、勋章管理和手动发放 | 勋章自动发放、复杂活动规则、核销报表 |
| 销售/代理客资 | 可联调 | 邀请码、扫码/分享事件、首绑保护、销售统计、客资明细、团队关系、手动补绑、分佣比例、归因、结算单、审核和打款状态 | 真实微信小程序码、真实打款、结算导出、销售团队看板 |
| CRM 系统 | 可联调 | CRM 配置、密钥私密存储、客资入队、队列查询、generic/钉钉/飞书/企微 worker、签名、重试和日志 | 定向/轮询分配、富卡片模板、失败告警、死信运营台 |
@@ -36,7 +36,7 @@
## 接下来优先级
1. 完善内容导入和对象存储:字段映射 UI、真实数据 dry-run、CDN 防盗链、杀毒扫描和视频水印。
1. 完善内容导入和对象存储:字段映射 UI、真实数据 dry-run、CDN 防盗链、真实 AV/内容安全 provider 和视频水印。
2. 公共题库/地区题库授权:已完成披露、采纳快照、手动同步、自动同步 worker、同步通知、冲突查询和租户自改保护继续补生产失败告警、冲突操作台增强和按 SaaS 套餐限制地区。
3. 学习统计增强:排行榜防刷/预聚合、断点续练、专项练习策略和更细题型分析。
4. 视频会员控制:深度防盗链、水印和播放统计。

View File

@@ -46,7 +46,7 @@
- 生产鉴权已具备 Supabase JWT API 入口,自定义角色模板基础 API 已可用;仍要做真实云端 Auth/JWKS 回归、RLS 深测和班级/学生范围权限细化,前端不要继续使用 `x-user-id`
- 不要把“Supabase 支持前端 Data API”误解为“本项目所有业务表都由 Taro 直写”订单、支付、权益、租户后台、导入、CRM、私有资源必须走 RPC、`apps/api`、Edge Function 或 worker 这类后端命令层。
- 短信、微信小程序/网页登录、QQ 登录、微信支付、支付宝支付 provider 已有本地 adapter 和测试覆盖;生产账号、回调域名、证书和商户资料仍需正式联调。
- 对象存储已完成签名 provider、上传后校验、PDF/图片预览资源复检 worker但 CDN 防盗链、视频水印和杀毒扫描还要补。
- 对象存储已完成签名 provider、上传后校验、PDF/图片预览资源复检 worker 和内置安全扫描,但 CDN 防盗链、视频水印和真实 AV/内容安全 provider 还要补。
- 题目/单词/知识手册/分数线/视频 JSON/CSV/Excel 导入已可联调;大批量导入可传 `executionMode=async` 交给 imports worker模板下载、字段映射 API、导入任务详情和导入后复检已可用。租户内容页已经可以选择文件或粘贴内容、下载模板、执行后端预览、编辑本次字段别名、同步/异步提交导入、轮询异步 job、查看问题行并触发/查看复检;后续还要补真实数据 dry-run 验收和更完整的目标入口/集合选择。
- 数据看板、分佣结算、勋章手动发放和主题模板发布基础 API 已可联调;勋章自动发放、分佣真实打款/导出/凭证、AI 择校、主题素材库/模板市场等仍是后续商用增强项。
@@ -87,7 +87,7 @@
| 工作台 | `apps/taro/src/pages/tenant-admin/workbench/index.tsx` | `tenant-admin/overview``tenant-admin/dashboard``tenant-admin/permissions` |
| 数据看板 | `apps/taro/src/pages/tenant-admin/dashboard/index.tsx` | `tenant-admin/dashboard` |
| 学生运营 | `apps/taro/src/pages/tenant-admin/students/index.tsx` | `tenant-admin/classes``tenant-admin/teachers``tenant-admin/students``students/bulk-upsert``students/status``classes/members/bulk-assign``students/notes``students/followups` |
| 题库内容 | `apps/taro/src/pages/tenant-admin/content/index.tsx` | `tenant-content/content-entries``tenant-content/imports``imports/detail``imports/issues``imports/field-mapping``imports/templates``imports/post-check``tenant-content/exports/questions``tenant-content/exports/jobs``tenant-content/assets/sign-download``tenant-content/assets/sign-preview``tenant-content/public-question-banks``public-question-banks/adopt``public-question-banks/sync``public-question-banks/conflicts``public-question-banks/conflicts/resolve``public-question-banks/conflicts/resolve-batch``tenant-content/notifications``tenant-content/notifications/status` |
| 题库内容 | `apps/taro/src/pages/tenant-admin/content/index.tsx` | `tenant-content/content-entries``tenant-content/imports``imports/detail``imports/issues``imports/field-mapping``imports/templates``imports/post-check``tenant-content/exports/questions``tenant-content/exports/jobs``tenant-content/assets/sign-download``tenant-content/assets/sign-preview``tenant-content/assets/security-scan-events``tenant-content/public-question-banks``public-question-banks/adopt``public-question-banks/sync``public-question-banks/conflicts``public-question-banks/conflicts/resolve``public-question-banks/conflicts/resolve-batch``tenant-content/notifications``tenant-content/notifications/status` |
| 营销中心 | `apps/taro/src/pages/tenant-admin/marketing/index.tsx` | `tenant-admin/coupons``code-batches``activation-codes``crm/config``crm/queue``commission/settings``member-rate``summary``orders``settlements``settlements/generate``settlements/status` |
| 租户设置 | `apps/taro/src/pages/tenant-admin/settings/index.tsx` | `tenant-admin/overview``domains``payment-accounts``auth-providers``theme-templates``theme``theme/preview``theme/publish``permissions``GET/PUT role-templates``POST role-templates/disable``GET/PUT members``POST members/disable` |

View File

@@ -32,7 +32,7 @@
| 知识手册 | 已建手册科目、章节、条目,并可绑定 `content_entries/content_nodes` | 已支持内容导入 | 只读 API、租户后台手册科目/章节/条目维护 API、嵌套 JSON 预览导入已实现 | 核心 API 集成测试含导入断言 | 学生端阅读、后台维护和批量 JSON 导入基础可用,富文本资源/版本管理待补 |
| 分数线 | 已建院校、专业、字段、记录表 | 已支持导入映射 | 字段、院校、专业、记录、趋势、年份、租户后台维护 API、JSON 预览导入已实现 | 核心 API 集成测试含导入断言 | 查询、后台维护和批量 JSON 导入基础闭环已实现,复杂动态筛选和 AI 择校上下文待补 |
| 题目视频讲解 | 已建 `video_explanations``question_videos` | 已支持导入映射 | 单题视频、批量预加载、通用视频搜索、播放签名、视频次数扣减、租户后台视频创建绑定 API、JSON 预览导入已实现 | 核心 API 集成测试含播放和导入断言 | 播放、权益、后台绑定和批量 JSON 导入链路已实现,深度防盗链、动态水印和播放统计待补 |
| 资料下载/PDF | 已扩展 `content_assets`,新增资源台账和导入任务表 | 旧 `app_assets/images` 兼容导入 | 租户后台资源管理、OSS/COS/Supabase Storage 上传/下载签名、上传确认、PDF/图片预览签名、题库导出 PDF/Word/每日一练 ZIP 自动发布资源、学生端资料列表/下载权限已实现 | 核心 API 集成测试含 SVIP 资料下载assets worker 和 exports worker 测试 | 资料资源基础闭环可跑CDN 防盗链、杀毒扫描和资料下载前端待补 |
| 资料下载/PDF | 已扩展 `content_assets`,新增资源台账和导入任务表 | 旧 `app_assets/images` 兼容导入 | 租户后台资源管理、OSS/COS/Supabase Storage 上传/下载签名、上传确认、PDF/图片预览签名、资源访问审计、内置安全扫描、题库导出 PDF/Word/每日一练 ZIP 自动发布可信资源、学生端资料列表/下载权限已实现 | 核心 API 集成测试含 SVIP 资料下载、安全扫描门禁assets worker 和 exports worker 测试 | 资料资源基础闭环可跑CDN 防盗链、真实 AV/内容安全 provider、动态水印和资料下载前端待补 |
| 个人中心 | 已建 `student_profiles`、会员权益、订单、练习记录、`badges/user_badges` | 已支持部分用户资料和勋章导入 | 个人资料、目标院校/专业、手机号绑定/换绑、会员状态、最近练习、统计聚合、签到积分、题目反馈、考试倒计时、勋章 API 已实现 | API 集成测试 | 学生端基础个人中心已实现,学习报告可视化和更细任务系统待补 |
| 活动/优惠 | 已建优惠券、激活码、激活码批次、banner、FAQ、公告、勋章等基础表 | 部分支持 | banner/FAQ/公告只读与租户后台维护、激活码预检查/兑换、激活码批次、批量生成激活码、优惠券维护、前台领取/下单抵扣、勋章维护和手动发放已实现 | 核心 API 集成测试 | 基础运营后台可用,勋章自动发放、复杂活动规则、营销自动化、核销报表待补 |
| 销售/代理客资追踪 | 已建推荐码、首绑客资、团队关系、小程序码缓存、CRM 队列 | 旧 `referral_tracks` 已有映射基础 | 邀请码、扫码/分享事件、首绑保护、销售统计、客资明细、手动补绑、团队关系、CRM 配置/队列、CRM worker 推送已实现 | 核心 API 集成测试、CRM worker 集成测试 | 增长链路基础可用真实微信小程序码、CRM 分配策略、富卡片和销售转化看板待补 |
@@ -295,7 +295,7 @@ platform-admin:
为了先把旧项目核心业务补齐,再进入支付/短信等商用关键模块,建议按下面顺序继续:
1. 完善内容导入和文件上传:字段映射 UI、真实数据 dry-run 执行验收、CDN 防盗链、杀毒扫描
1. 完善内容导入和文件上传:字段映射 UI、真实数据 dry-run 执行验收、CDN 防盗链、真实 AV/内容安全 provider
2. 补公共题库生产定时调度/失败告警、租户套餐地区/科目/题库范围限制、主题模板系统。
3. 补学习统计增强:排行榜防刷/预聚合、断点续练、专项练习策略和更细题型分析。
4. 补视频商用控制:深度防盗链、动态水印和播放统计。

View File

@@ -32,7 +32,7 @@
| 分数线 | `ScorelinePage.tsx` | 已覆盖 | 动态字段/趋势、后台维护和 JSON 批量导入已有;后续补复杂筛选优化和 AI 择校数据上下文 |
| 商城/SVIP | `Store.tsx``SvipModal.tsx` | 部分覆盖 | 套餐、订单、订单详情/状态轮询、权益、激活码预检查/兑换、优惠券领取/下单抵扣、微信支付/支付宝 provider 主链路、内部退款状态机、微信/支付宝发起退款、退款查询确认、退款通知 webhook、支付/退款补偿 worker、全额退款权益撤销、资金对账手工/API 导入比对、异常查询、差错工单和事件轨迹已有;缺微信/支付宝官方账单自动下载、异常订单运营台和前端收银台/售后体验 |
| 个人中心 | `Profile.tsx` | 部分覆盖 | 基本资料、手机号绑定/换绑、权益、订单统计、练习历史、学习统计、签到积分、考试倒计时、趋势和勋章展示 API 已有;缺学习报告可视化 |
| 资料下载 | `QuestionExporterPublishModal.tsx` 等 | 部分覆盖 | 资源台账、上传确认、签名下载PDF/图片预览基础已有;缺水印、防盗链、杀毒扫描和 worker 复检 |
| 资料下载 | `QuestionExporterPublishModal.tsx` 等 | 部分覆盖 | 资源台账、上传确认、签名下载PDF/图片预览、worker 复检和内置安全扫描已有;缺动态水印、深度防盗链、真实 AV/内容安全 provider 和生命周期策略 |
| AI 择校推荐 | 业务规划新增 | 未覆盖 | 需设计学生输入 schema、地区数据上下文、AI JSON 输出、PDF 报告 |
| 题目反馈 | `02-API接口.md` 用户反馈 | 部分覆盖 | 学生提交、本人列表、租户后台处理、状态事件、反馈奖励积分已覆盖;缺处理通知、前端消息提醒和批量统计 |
| 签到积分 | `Profile.tsx``02-API接口.md` | 部分覆盖 | 每日签到、连续签到基础、积分流水、重复签到幂等已覆盖;缺积分兑换、活动任务和更完整的运营规则 |
@@ -66,7 +66,7 @@
| 分数线维护 | 已覆盖 | 字段/院校/专业/记录 CRUD 和 JSON 批量导入已有 |
| 视频维护/绑定 | 已覆盖 | video CRUD、question-video 绑定和视频 JSON 批量导入已有 |
| CRM 配置和队列 | 部分覆盖 | 配置/队列已有;钉钉/飞书/企微真实发送 worker、签名、重试、死信待补 |
| 对象存储配置 | 部分覆盖 | 系统 env provider、上传签名、上传确认预览下载签名已有租户级存储策略、CDN/水印/杀毒待补 |
| 对象存储配置 | 部分覆盖 | 系统 env provider、上传签名、上传确认预览下载签名、资源访问审计和内置安全扫描已有租户级存储策略、CDN/水印/真实 AV provider 待补 |
## 平台 SaaS 后台功能
@@ -117,7 +117,7 @@
### P1商用主链路
1. 微信/支付宝支付和 webhook 幂等。
2. 对象存储 PDF 预览、视频深度防盗链、动态水印。
2. 对象存储真实 AV/内容安全 provider、视频深度防盗链、动态水印。
3. 真实数据 dry-run 执行验收、导入抽样校验和性能压测。
4. 数据看板预聚合 worker、销售/代理转化看板和分佣结算。
5. 公共题库生产定时调度、失败告警、租户确认/跳过策略和更完整运营消息。

View File

@@ -28,7 +28,7 @@
- 租户后台数据看板已完成首版聚合 API`GET /api/tenant-admin/dashboard`,支持租户/地区维度的收益、注册、学习、内容、激活码、反馈、趋势、24h 活跃、套餐销量和运营动态,前端可直接联调。
- 支付/退款补偿 worker 已完成:`apps/worker --job commerce` 可查询微信/支付宝支付和处理中退款,补偿漏通知订单,支付成功幂等开通权益,退款成功幂等更新退款/订单/支付并在全额退款时撤销订单权益。
- 资金对账和差错工单闭环已完成:`commerce_reconciliation_batches/items``/api/commerce/reconciliation/*` 支持手工/API 导入供应商账单行、预览差异、生成批次统计、查询异常、租户隔离、权限点 `tenant:reconciliation:read/write` 和审计日志;`commerce_reconciliation_issues/events` 支持异常明细创建工单、分配、开始处理、升级、解决、忽略、重开和事件留痕,且不直接修改订单/支付/退款/权益。
- 内容资源复检 worker 已完成:`apps/worker --job assets` 可复检 `content_assets` 中的托管对象元数据,正常资源写回复检证据,异常资源自动置为 `failed + draft` 并写入审计和安全标记。
- 内容资源复检与安全扫描 worker 已完成:`apps/worker --job assets` 可复检 `content_assets` 中的托管对象元数据,并执行内置 `metadata_rules` 安全扫描;正常资源写回复检/扫描证据,异常资源自动置为 `failed/skipped + draft` `security_scan_status=failed`,并写入审计、扫描事件和安全标记。
- 题库导出 worker 已完成:`apps/worker --job exports` 可抢占 `pdf/docx/daily_practice_zip` 导出任务,渲染 PDF/Word、水印或每日一练图片素材包写入对象存储或本地开发存储创建 `content_assets` 并回填 `assetId/hash/size``daily_practice` 已支持每日一练九宫格 metadata、PDF/Word 基础版式、9 张 PNG/SVG 卡片和拼图 ZIP。
- 本地验证:`npm run check:refactor` 已通过。
@@ -50,9 +50,10 @@
- 已接阿里云 OSS、腾讯云 COS、Supabase Storage 的上传/下载签名 provider。
- 已补上传后对象确认接口、托管对象发布前 verified 校验、PDF/图片 inline 预览签名。
- 已补 assets worker 复检,异常托管对象会自动下架并记录审计。
- 已补内容资源安全扫描状态机:确认上传后进入 `securityScanStatus=pending`,扫描通过后才能发布、下载、预览或视频播放;后台可查 `/api/tenant-content/assets/security-scan-events`
- 已补资源访问事件 `content_asset_access_events`,覆盖上传签名/确认、学生下载/预览、后台下载/预览的 granted/denied、短 TTL、签名模式、IP 和 UA。
- 已收紧锁定资源 CDN 边界:`members/svip/private` 外链默认拒绝,必须显式 provider-managed 才允许;视频绑定资源也复用该策略。
- 继续补动态水印、杀毒扫描、CDN 刷新和对象生命周期策略。
- 继续补真实 AV/内容安全 provider、动态水印、CDN 刷新和对象生命周期策略。
- `content_assets` 继续作为资源台账,不允许前端绕过台账直接访问私有资源。
3. 真实导入 dry-run
@@ -225,5 +226,5 @@
3. 补平台后台增强:租户详情/编辑、平台审计报表、自动计费、账单批量操作和更细平台权限点。
4. 云服务器部署 Supabase/PostgreSQL 和 API配置对象存储生产环境变量`check:refactor` 的远程等价测试。
5. 导出现有 PocketBase 数据,做完整 dry-run 迁移。
6. 并行补真实登录、微信/支付宝官方账单自动下载、异常订单运营台、对象存储杀毒/水印/生命周期、题库导出模板精排/操作台、公共题库生产定时调度和失败告警。
6. 并行补真实登录、微信/支付宝官方账单自动下载、异常订单运营台、对象存储真实 AV/内容安全 provider、水印/生命周期、题库导出模板精排/操作台、公共题库生产定时调度和失败告警。
7. 前后端联调通过后,再做支付、权限、数据导入、资料下载、视频播放的商用验收。

View File

@@ -28,7 +28,7 @@ POST /api/tenant-content/assets/sign-upload
PUT /api/tenant-content/assets
```
后台确认上传并发布
后台确认上传:
```text
POST /api/tenant-content/assets/confirm-upload
@@ -58,6 +58,12 @@ POST /api/videos/play
GET /api/tenant-content/assets/access-events?assetId=...
```
后台查看资源安全扫描事件:
```text
GET /api/tenant-content/assets/security-scan-events?assetId=...
```
后台管理员下载:
```text
@@ -90,11 +96,13 @@ npm --workspace @tiku-saas/worker run exports:once
2. 前端使用返回的 `upload.url``upload.headers` 直传对象存储。
3. 调用 `PUT /api/tenant-content/assets` 登记资源台账。托管对象默认进入 `status=draft``uploadStatus=pending`
4. 调用 `POST /api/tenant-content/assets/confirm-upload`由后端读取对象元数据并比对大小、MIME、SHA-256。
5. 校验通过`publish=true` 时,后端将资源置为 `status=active``uploadStatus=verified`
6. 学生端只能下载或预览 `active + verified` 的托管对象资源
7. 学生端和后台管理员下载/预览都会写入 `content_asset_access_events`,包含 `assetId/userId/accessType/result/expiresInSec/signatureMode/ip/userAgent` 等审计字段
8. 生产环境定时运行 assets worker复检 `pending/verified` 托管对象的大小、MIME、SHA-256 等元数据
9. 如果复检发现对象丢失、跨租户 objectKey、大小/MIME/checksum 不一致worker 会把资源置为 `uploadStatus=failed`,并将 `active` 资源退回 `draft`,同时写入 `security_flags.assetRecheckFailed=true``audit_logs`
5. 校验通过后,后端只会置为 `uploadStatus=verified``securityScanStatus=pending`,并继续保持 `status=draft`。即使请求里传 `publish=true`,也不会绕过安全扫描直接发布
6. 运行 assets worker。worker 会先复检对象元数据,再执行内置 `metadata_rules` 安全扫描,检查 object key、MIME allowlist、文件大小、扩展名/MIME 是否匹配等规则
7. 扫描通过后,资源变为 `securityScanStatus=passed`,后台再调用 `PUT /api/tenant-content/assets``status=active` 发布
8. 学生端只能下载或预览 `active + uploadStatus=verified + securityScanStatus=passed` 托管对象资源;后台管理员下载/预览也执行同一安全扫描门禁
9. 学生端和后台管理员下载/预览都会写入 `content_asset_access_events`,包含 `assetId/userId/accessType/result/expiresInSec/signatureMode/ip/userAgent` 等审计字段
10. 生产环境定时运行 assets worker复检 `pending/verified` 托管对象的大小、MIME、SHA-256 等元数据。
11. 如果复检发现对象丢失、跨租户 objectKey、大小/MIME/checksum 不一致worker 会把资源置为 `uploadStatus=failed``securityScanStatus=skipped`,并将 `active` 资源退回 `draft`,同时写入 `security_flags.assetRecheckFailed=true``content_asset_security_scan_events``audit_logs`
## 题库导出生成资源
@@ -104,7 +112,7 @@ npm --workspace @tiku-saas/worker run exports:once
2. API 校验租户内容权限、导出范围和答案/解析开关,创建 `content_export_jobs.status=pending`
3. `apps/worker --job exports` 抢占 pending job复用后端导出 payload 规则渲染 PDF/Word或为每日一练生成 ZIP 素材包PDF/Word 会应用 `options.watermarkText` 水印ZIP 包会包含 PNG/SVG 卡片、拼图、manifest 和脱敏 payload。
4. worker 将二进制文件写入配置的对象存储。`local_dev` 会写入 `EXPORT_LOCAL_STORAGE_ROOT`,生产建议使用 `supabase_storage``aliyun_oss``tencent_cos`
5. worker 创建 `content_assets`,设置 `uploadStatus=verified`,并把 `assetId`、文件名、大小和 SHA-256 回填到 `content_export_jobs.output_metadata`
5. worker 创建 `content_assets`,设置 `uploadStatus=verified``securityScanStatus=passed``securityScanProvider=trusted_export_worker`,并把 `assetId`、文件名、大小和 SHA-256 回填到 `content_export_jobs.output_metadata`
6. 前端轮询 `GET /api/tenant-content/exports/jobs`,拿到 `assetId` 后通过 `POST /api/tenant-content/assets/sign-download``sign-preview` 下载/预览。
注意PDF/Word/ZIP 文件本身不直接存入数据库,数据库只保存 job、资源台账和校验 metadata。`daily_practice_zip` 资源类型为 `package`,通常只做签名下载,不做 inline 预览。
@@ -129,6 +137,8 @@ npm --workspace @tiku-saas/worker run exports:once
- `supabase_storage` 使用 Storage list metadata 做最小存在性/大小校验。
- 如果 provider 无法返回 SHA-256后端会记录 `checksumUnavailable=true`,生产建议上传时写入对象自定义元数据,例如 `x-oss-meta-sha256``x-cos-meta-sha256`
- worker 的复检证据写入 `verification_details.assetWorker`,包含 `lastCheckedAt``lastResult``expected``observed``issues`,便于租户后台定位资源异常。
- `publish=true` 只作为迁移期兼容参数保留。确认上传成功后仍然会保持草稿,必须等 `securityScanStatus=passed` 后再由后台显式发布。
- 新上传托管对象常见状态流为:`draft/pending/pending` -> `draft/verified/pending` -> `draft/verified/passed` -> `active/verified/passed`
## 安全规则
@@ -136,7 +146,8 @@ npm --workspace @tiku-saas/worker run exports:once
- `objectKey` 默认必须以当前 `tenantId/` 开头,防止跨租户覆盖或读取。
- 禁止 `..`、反斜杠、编码斜杠等危险 object key。
- 上传会校验 MIME 类型和文件大小。
- 托管对象资源未确认前不能发布为 `active`,学生端不可下载。
- 托管对象资源未确认或安全扫描未通过前不能发布为 `active`,学生端不可下载。
- 托管对象安全扫描失败会返回 `ASSET_SECURITY_SCAN_FAILED`;仍在等待扫描或扫描被跳过会返回 `ASSET_SECURITY_SCAN_REQUIRED`
- PDF/图片预览使用 `inline` 签名,不等同于长期公开 URL。
- 下载、预览和视频播放必须先经过 API 权限判断,再下发短期签名 URL。
- 学生端 `preview`、锁定资料下载、视频和资料包默认使用更短 TTL。当前策略是学生 inline 预览、`members/svip/private` 资料、`video/package` 资源最多 300 秒;租户后台预览最多 3600 秒,后台下载最多 86400 秒。
@@ -144,7 +155,43 @@ npm --workspace @tiku-saas/worker run exports:once
- 每次上传签名、上传确认、学生下载/预览、后台下载/预览都会写入 `content_asset_access_events`。授权失败也会记录 `result=denied``denyCode`,用于租户后台排查资源访问问题。
- 云厂商 AccessKey、SecretKey、Service Role Key 只存在服务端环境变量,不返回前端。
- `content_assets` 是资源唯一台账,前端不得绕过台账直接访问私有 bucket。
- 前端不能把 `uploadStatus=failed``status=draft` 的资源继续展示为可下载;列表仍返回时应展示“资料处理中”或“资源异常已下架”,真正下载/预览会被后端拒绝。
- 前端不能把 `uploadStatus=failed``securityScanStatus!=passed``status=draft` 的资源继续展示为可下载;列表仍返回时应展示“资料处理中”“安全扫描中”或“资源异常已下架”,真正下载/预览会被后端拒绝。
## 安全扫描字段
资源台账 `content_assets` 新增安全扫描状态:
| 字段 | 说明 |
| --- | --- |
| `security_scan_status` | `not_required/pending/scanning/passed/failed/skipped` |
| `security_scanned_at` | 最近一次扫描完成时间 |
| `security_scan_provider` | 扫描来源,例如 `metadata_rules``trusted_export_worker` |
| `security_scan_summary` | 风险等级、问题码、扫描证据和失败原因 |
当前内置 provider 是 `metadata_rules`。它不是完整杀毒引擎,但能阻断明显危险或不合规对象:跨租户 key、非法 object key、超限文件、MIME allowlist 外文件、扩展名/MIME 不匹配,以及测试/运营标记的强制失败。商用生产仍需继续接入真实 AV/内容安全 provider并将结果写入同一张事件表。
扫描事件表:
```text
public.content_asset_security_scan_events
```
后台接口:
```text
GET /api/tenant-content/assets/security-scan-events?assetId=<assetId>&limit=100
```
事件字段:
| 字段 | 说明 |
| --- | --- |
| `asset_id` | 资源 ID |
| `provider` | 扫描 provider |
| `scan_status` | `pending/scanning/passed/failed/skipped` |
| `risk_level` | `none/low/medium/high/critical` |
| `issue_codes` | 问题码数组,例如 `file_extension_mime_mismatch` |
| `details` | observed/declared metadata、扩展名、错误信息等证据 |
## 访问事件字段

View File

@@ -902,14 +902,16 @@ GET /api/catalog/assets/download?assetId=<assetId>
- `download.url` 是短期 attachment URL只给下载动作使用。
- `ASSET_SVIP_REQUIRED`:提示开通对应地区/科目权益。
- `ASSET_UPLOAD_NOT_VERIFIED`:展示“资料正在处理中”,并上报前端日志。
- `ASSET_SECURITY_SCAN_REQUIRED`:展示“资料安全扫描中,请稍后再试”,并重新拉取资源列表或提示后台处理。
- `ASSET_SECURITY_SCAN_FAILED`:展示“资料安全校验未通过,已下架”,学生端不要继续重试旧签名。
- `ASSET_NOT_FOUND` 或列表中资源从 `active` 消失:展示“资源异常已下架”或刷新列表,不要继续使用旧签名 URL。
- `ASSET_PREVIEW_NOT_SUPPORTED`:隐藏预览按钮,仅保留下载或提示不支持预览。
- `previewUrl` 字段只作为公开/托管预览提示,不代表可以绕过接口直接访问。
租户后台上传资料必须走步:
租户后台上传资料必须走步:
```text
sign-upload -> 直传对象存储 -> PUT assets 登记草稿 -> confirm-upload -> sign-preview 验收
sign-upload -> 直传对象存储 -> PUT assets 登记草稿 -> confirm-upload -> 等待 assets worker 安全扫描 -> PUT assets 发布 -> sign-preview 验收
```
后台上传确认:
@@ -924,9 +926,29 @@ sign-upload -> 直传对象存储 -> PUT assets 登记草稿 -> confirm-upload -
}
```
托管对象在确认前会保持 `status=draft``uploadStatus=pending`,学生端不会看到。确认失败时后端返回 `UPLOAD_VERIFICATION_FAILED`,后台必须展示失败原因并允许重新上传,不能前端强行改为已发布。
托管对象在确认前会保持 `status=draft``uploadStatus=pending``securityScanStatus=pending`,学生端不会看到。确认成功后仍保持 `status=draft`,并进入 `uploadStatus=verified``securityScanStatus=pending`;即使传 `publish=true`,后端也不会直接发布。确认失败时后端返回 `UPLOAD_VERIFICATION_FAILED`,后台必须展示失败原因并允许重新上传,不能前端强行改为已发布。
生产环境会定时运行 assets worker 复检对象存储元数据。复检发现对象丢失、跨租户 objectKey、大小/MIME/checksum 不一致时,后端会把资源置为 `uploadStatus=failed` 并从 `active` 退回 `draft`,同时写入 `securityFlags.assetRecheckFailed=true`。租户后台资源列表应对 failed 资源展示异常原因和重新上传入口;学生端不要缓存资料列表和签名 URL 作为长期状态
后台资源列表建议展示这些状态
| 状态 | 前端展示 | 可执行动作 |
| --- | --- | --- |
| `draft/pending/pending` | 待上传确认 | 重新上传、确认上传 |
| `draft/verified/pending` | 安全扫描排队中 | 刷新状态、查看扫描事件 |
| `draft/verified/scanning` | 安全扫描中 | 刷新状态、查看扫描事件 |
| `draft/verified/passed` | 可发布 | 发布、预览、下载 |
| `active/verified/passed` | 已发布 | 预览、下载、下架 |
| `draft/verified/failed` | 安全扫描失败 | 查看扫描事件、重新上传 |
| `draft/failed/skipped` | 上传复检失败 | 查看复检/扫描事件、重新上传 |
租户后台可通过下面接口排查扫描过程:
```http
GET /api/tenant-content/assets/security-scan-events?assetId=<assetId>&limit=100
```
`GET /api/tenant-content/assets` 和学生端 `GET /api/catalog/assets` 都会返回 `securityScanStatus`。前端可以展示状态,但最终能否下载、预览、播放仍以后端签名接口为准。
生产环境会定时运行 assets worker 复检对象存储元数据并执行内置 `metadata_rules` 安全扫描。复检发现对象丢失、跨租户 objectKey、大小/MIME/checksum 不一致时,后端会把资源置为 `uploadStatus=failed``securityScanStatus=skipped` 并从 `active` 退回 `draft`,同时写入 `securityFlags.assetRecheckFailed=true`。扫描发现 MIME 不允许、扩展名/MIME 不匹配等问题时,会把资源置为 `securityScanStatus=failed`,并写入 `securityFlags.assetSecurityScanFailed=true`。租户后台资源列表应对 failed/skipped 资源展示异常原因和重新上传入口;学生端不要缓存资料列表和签名 URL 作为长期状态。
## 考试倒计时、签到积分和反馈