diff --git a/README.md b/README.md index 2a398e60..f460ac09 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,11 @@ - `docs/refactor/content-import-contract.md` - `docs/refactor/object-storage.md` - `docs/refactor/project-structure.md` +- `docs/refactor/frontend-handoff-index.md` +- `docs/refactor/backend-capability-status.md` +- `docs/refactor/legacy-feature-gap-matrix.md` +- `docs/refactor/taro-frontend-integration.md` +- `docs/refactor/multitenant-auth-security-contract.md` - `docs/refactor/next-development-todo.md` - `docs/refactor/blueprint-coverage.md` - `docs/refactor/api-structure.md` @@ -167,8 +172,8 @@ npm run check:refactor 优先继续补: -1. 对象存储上传后校验、PDF 预览、防盗链和视频水印。 -2. Excel/CSV 以及分数线、视频批量导入;把现有 JSON 导入升级为可排队异步执行。 -3. Supabase Auth/JWT 正式鉴权和生产 RLS 验证。 -4. 微信/QQ 登录、短信、微信支付、支付宝支付 adapter。 -5. Taro 前端 scaffold,让 H5 和小程序共用同一套 API。 +1. Supabase Auth/JWT 正式鉴权、生产配置 fail-fast、请求体大小限制和租户隔离回归测试。 +2. Taro 前端 scaffold,让 H5 和小程序共用同一套 API。 +3. 对象存储上传后校验、PDF 预览、防盗链和视频水印。 +4. Excel/CSV 以及分数线、视频批量导入;把现有 JSON 导入升级为可排队异步执行。 +5. 微信/QQ 登录、短信、微信支付、支付宝支付 adapter。 diff --git a/docs/refactor/README.md b/docs/refactor/README.md index d2c24902..c24ec227 100644 --- a/docs/refactor/README.md +++ b/docs/refactor/README.md @@ -21,11 +21,16 @@ - `docs/refactor/content-import-contract.md`:题目、单词、知识手册导入契约,明确后端校验、旧格式转换和前端职责。 - `docs/refactor/next-development-todo.md`:后端剩余缺口、Taro 前端接入顺序、上云测试前待办。 - `docs/refactor/backend-handoff-roadmap.md`:进入 Taro 前端前的后端进度同步、缺口清单和接入路线图。 +- `docs/refactor/frontend-handoff-index.md`:交给前端同事的阅读入口和当前可开工范围。 +- `docs/refactor/backend-capability-status.md`:后端已覆盖、迁移期、待补齐能力盘点。 +- `docs/refactor/legacy-feature-gap-matrix.md`:对照旧题库功能的新后端差距矩阵。 +- `docs/refactor/taro-frontend-integration.md`:Taro/H5/小程序启动、请求封装、页面/API 映射。 +- `docs/refactor/multitenant-auth-security-contract.md`:多租户隔离、鉴权、权限和资源安全红线。 下一步优先级: -1. 先按 `docs/refactor/backend-handoff-roadmap.md` 的 P0 清单补齐上云测试和 Taro 主链路所需能力。 -2. 导出 PocketBase 真实数据到 `pb_export/*.json`,执行 `npm run pb:import:json` 和 `npm run pb:import:validate`。 -3. 新建 `apps/taro`,优先接租户解析、首页、题库练习、背单词、知识手册、个人中心。 +1. 先按 `docs/refactor/multitenant-auth-security-contract.md` 的 P0 清单补齐鉴权、生产配置和租户隔离测试。 +2. 新建 `apps/taro`,按 `docs/refactor/taro-frontend-integration.md` 优先接租户解析、首页、题库练习、背单词、知识手册、个人中心。 +3. 导出 PocketBase 真实数据到 `pb_export/*.json`,执行 `npm run pb:import:json` 和 `npm run pb:import:validate`。 4. 为对象存储、分数线、视频、Excel/CSV 补齐 provider/导入能力,并复用 `content_import_jobs` 管线。 5. 接真实短信、微信/QQ 登录、微信支付/支付宝和 CRM worker,进入商用验收。 diff --git a/docs/refactor/backend-capability-status.md b/docs/refactor/backend-capability-status.md new file mode 100644 index 00000000..9e14f3d3 --- /dev/null +++ b/docs/refactor/backend-capability-status.md @@ -0,0 +1,156 @@ +# 后端当前能力盘点 + +更新时间:2026-06-28 + +当前后端已经完成商用 SaaS 题库系统的主干骨架:PostgreSQL 多租户 schema、Node.js 业务 API、PocketBase 数据导入工具、本地 seed、API 集成测试和对象存储签名 provider。 + +状态分为: + +- `可联调`:前端可以开始接入,本地测试已覆盖主链路。 +- `迁移期`:能支撑开发联调,但生产前必须替换或加固。 +- `待补齐`:旧题库已有或商用交付需要,但新后端还没完整实现。 + +## 基础工程 + +| 模块 | 状态 | 说明 | +| --- | --- | --- | +| Supabase/PostgreSQL schema | 可联调 | `supabase/migrations` 已包含多租户、题库、学习、订单、内容、CRM、平台账务等表 | +| RLS/租户隔离 | 迁移期 | 表层普遍有 `tenant_id` 和 RLS 策略,但 API 目前使用服务端连接,生产前要补真实 JWT/RLS 回归 | +| API 分层 | 可联调 | `apps/api/src/core` + `apps/api/src/features/*` | +| Docker API | 可联调 | `docker-compose.api.yml` 和 `apps/api/Dockerfile` 可用 | +| 测试 | 可联调 | `npm run check:refactor` 覆盖 TS 检查、导入校验、seed、API 集成测试 | +| 根 workspace | 可联调 | 根目录已清理为新技术栈 monorepo 编排层 | + +## 租户与品牌 + +| 能力 | 状态 | 后端接口/模型 | +| --- | --- | --- | +| 域名/小程序码解析租户 | 可联调 | `GET /api/tenant/resolve` | +| 品牌名、Logo、客服、主题 JSON | 可联调 | `tenant_branding`、`tenant_settings` | +| 功能开关 | 可联调 | `features`、`adminFeatures` | +| 自定义域名管理 | 可联调 | `GET/POST /api/tenant-admin/domains` | +| 多套主题模板 | 待补齐 | 当前只有租户 theme JSON,缺平台主题模板、预览、发布流程 | + +## 鉴权与权限 + +| 能力 | 状态 | 说明 | +| --- | --- | --- | +| 短信验证码登录 | 迁移期 | 已有验证码、冷却、hash、登录事件;mock provider 可本地联调 | +| 迁移期 session | 迁移期 | `tk_` token hash 存在 `app_private.auth_sessions` | +| 微信/QQ OAuth | 待补齐 | 目前是 placeholder | +| 平台管理员鉴权 | 迁移期 | 当前用 `x-platform-admin-key`,生产前必须换 JWT/服务端会话 | +| 租户角色权限 | 可联调 | `tenant_memberships.role + permissions`,接口有权限点校验 | +| 自定义角色模板 | 待补齐 | 当前有权限 JSON 覆盖,缺角色模板、菜单/模块/字段级权限配置 UI/API | + +## 学生端题库主链路 + +| 能力 | 状态 | 后端接口/模型 | +| --- | --- | --- | +| 地区/科目/分类兼容查询 | 可联调 | `/api/catalog/regions`、`subjects`、`categories` | +| 新内容入口 | 可联调 | `/api/catalog/content-entries` | +| 任意深度分类树 | 可联调 | `/api/catalog/content-nodes` | +| 题目列表/集合 | 可联调 | `/api/catalog/question-collections`、`question-collections/questions` | +| 顺序/随机/全真模拟规则 | 可联调 | `/api/catalog/practice-blueprints` | +| 创建练习 session | 可联调 | `POST /api/learning/practice-sessions` | +| 答题记录 | 可联调 | `POST /api/learning/answers` | +| 错题本 | 可联调 | `/api/learning/wrong-questions` | +| 收藏夹 | 可联调 | `/api/learning/favorites/questions` | +| 免费用户题量限制 | 待补齐 | 旧项目有保护逻辑,新后端需按租户/套餐/内容范围实现 | +| 模考交卷报告 | 待补齐 | 已有 session/answer 基础,缺完整交卷、评分报告、错题解析汇总 | + +## 背单词、知识手册、分数线、视频 + +| 能力 | 状态 | 后端接口/模型 | +| --- | --- | --- | +| 单词单元/单词列表 | 可联调 | `/api/catalog/vocabulary-units`、`vocabulary-words` | +| 单词进度/收藏/统计 | 可联调 | `/api/learning/vocabulary/*` | +| 艾宾浩斯复习算法 | 待补齐 | 当前有 next_review 字段基础,缺完整算法和每日计划 | +| 知识手册目录/内容 | 可联调 | `/api/catalog/handbook-*` | +| 知识手册 JSON 导入 | 可联调 | `/api/tenant-content/imports/*/handbook` | +| 分数线字段/院校/专业/记录/趋势 | 可联调 | `/api/scoreline/*` | +| 题目视频/批量预加载/搜索 | 可联调 | `/api/questions/*/videos`、`/api/videos/search` | +| 视频会员播放次数 | 待补齐 | 缺播放次数扣减、播放日志、防盗链、水印 | + +## 资料与对象存储 + +| 能力 | 状态 | 说明 | +| --- | --- | --- | +| 内容资源台账 | 可联调 | `content_assets` | +| 租户后台资源维护 | 可联调 | `/api/tenant-content/assets` | +| 学生端资源列表/下载签名 | 可联调 | `/api/catalog/assets`、`/api/catalog/assets/download` | +| 阿里云 OSS 签名 | 可联调 | `aliyun_oss` provider | +| 腾讯 COS 签名 | 可联调 | `tencent_cos` provider | +| Supabase Storage 签名 | 可联调 | `supabase_storage` provider | +| PDF 预览/防盗链/水印 | 待补齐 | 商用上线前补齐 | +| 上传后对象校验 | 待补齐 | 需 worker 或 API 回调确认 size/hash/mime | + +## 订单、会员、营销 + +| 能力 | 状态 | 说明 | +| --- | --- | --- | +| SVIP 套餐 | 可联调 | `/api/catalog/svip-plans` | +| 创建订单/订单列表 | 可联调 | `/api/commerce/orders` | +| 手工支付确认 | 迁移期 | 可用于测试,不是生产支付 | +| 权益查询/校验 | 可联调 | `/api/commerce/entitlements` | +| 激活码兑换 | 可联调 | 事务开通权益 | +| 优惠券后台配置 | 可联调 | `/api/tenant-admin/coupons` | +| 优惠券前台兑换/下单抵扣 | 待补齐 | 后端还需接入下单计算 | +| 微信/支付宝/小程序支付 | 待补齐 | 需 provider、验签、幂等、退款、补偿 | + +## 租户后台与平台后台 + +| 能力 | 状态 | 后端接口 | +| --- | --- | --- | +| 租户概览、品牌、设置 | 可联调 | `/api/tenant-admin/overview`、`branding`、`settings` | +| 商户收款配置 | 可联调 | `/api/tenant-admin/payment-accounts` | +| 登录 provider 配置 | 可联调 | `/api/tenant-admin/auth-providers` | +| 密钥掩码/引用 | 迁移期 | API 有掩码,生产前要做 KMS/Vault 或 envelope encryption | +| 活动、Banner、FAQ、公告 | 可联调 | `/api/tenant-admin/banners`、`faqs`、`announcements` | +| 激活码批次/生成/列表 | 可联调 | `/api/tenant-admin/code-batches`、`activation-codes` | +| 成员/角色权限/审计 | 可联调 | `/api/tenant-admin/members`、`permissions`、`audit-logs` | +| 平台租户/套餐/订阅/账单/用量 | 可联调 | `/api/platform-admin/*` | +| 数据看板聚合接口 | 待补齐 | 表基础已有,缺完整 dashboard API | + +## 销售、代理、CRM + +| 能力 | 状态 | 说明 | +| --- | --- | --- | +| 邀请码/二维码记录 | 可联调 | `/api/referral/invite-code`、`qrcode` | +| 扫码/分享事件 | 可联调 | `/api/referral/track-event` | +| 首绑客资保护 | 可联调 | `/api/referral/bind` | +| 手工补绑 | 可联调 | 需要 `referral:write` | +| 销售统计/客户列表/团队 | 可联调 | `/api/referral/sales-*`、`team` | +| CRM 配置/队列 | 可联调 | `/api/crm/config`、`/api/crm/queue` | +| 真实 CRM webhook worker | 待补齐 | 钉钉/飞书/企微发送、签名、重试、死信 | +| 分佣结算 | 待补齐 | 缺佣金规则、结算单、审核、导出 | + +## 内容导入与迁移 + +| 能力 | 状态 | 说明 | +| --- | --- | --- | +| PocketBase schema 分析 | 可联调 | `scripts/import-pocketbase` | +| 题目 JSON preview/import | 可联调 | 后端负责规范化、issue、幂等、审计 | +| 单词 JSON preview/import | 可联调 | 兼容旧模板 | +| 知识手册 JSON preview/import | 可联调 | 支持书籍/章节/小节/知识点归一化 | +| Excel/CSV 导入 | 待补齐 | 应复用 `content_import_jobs` 管线 | +| 分数线/视频批量导入 | 待补齐 | 应复用同一导入管线 | +| 大批量异步导入 | 待补齐 | 需要 `apps/worker` | + +## 当前验证 + +最近已通过: + +```bash +npm audit +npm run check:refactor +``` + +`check:refactor` 包含: + +- API TypeScript 检查 +- importer TypeScript 检查 +- PocketBase 导入校验 +- smoke seed +- API build +- API integration tests + diff --git a/docs/refactor/frontend-handoff-index.md b/docs/refactor/frontend-handoff-index.md new file mode 100644 index 00000000..afe14308 --- /dev/null +++ b/docs/refactor/frontend-handoff-index.md @@ -0,0 +1,48 @@ +# 前端交接索引 + +更新时间:2026-06-28 + +这份文件是给 Taro/H5/小程序前端同事的入口。当前仓库的前端重构建议从 `apps/taro` 新建工程开始,不再把旧 React/Vite 前端搬回根目录继续开发。 + +## 必读顺序 + +1. `docs/refactor/project-structure.md` + - 先确认新项目目录边界,避免把 `参考/旧题库项目` 当成新源码。 +2. `docs/refactor/backend-capability-status.md` + - 看哪些后端能力已经能联调,哪些只是迁移期可用。 +3. `docs/refactor/legacy-feature-gap-matrix.md` + - 对照旧题库功能,确认哪些页面能按新 API 重做,哪些后端还要补。 +4. `docs/refactor/taro-frontend-integration.md` + - Taro 启动、租户解析、请求封装、页面/API 映射、跨端注意事项。 +5. `docs/refactor/multitenant-auth-security-contract.md` + - 多租户、鉴权、权限、资源签名和生产安全红线。 +6. `docs/refactor/content-import-contract.md` + - 后台内容导入、题目 JSON、单词、知识手册的后端校验契约。 + +## 当前可进入的前端工作 + +- 可以开始搭建 `apps/taro`。 +- 可以复刻旧题库学生端主要视觉和交互:登录、选地区、首页、刷题、背单词、知识手册、分数线、资料、商城、个人中心。 +- 可以按新后端主模型接入内容导航: + - `content_entries` + - `content_nodes` + - `question_collections` + - `practice_blueprints` +- 可以接入迁移期短信登录和 `tk_` session,用于本地/内网联调。 +- 可以接入租户品牌、主题、功能开关和域名/小程序参数解析。 + +## 不能误认为已商用完成的部分 + +- 生产鉴权尚未完成:当前很多接口仍用 `x-tenant-id`、`x-user-id`、`x-platform-admin-key` 作为迁移期上下文。 +- 真实短信、微信登录、QQ 登录、微信支付、支付宝支付 provider 还未正式接完。 +- 对象存储已完成签名 provider,但 PDF 预览、防盗链、视频水印、上传后校验还要补。 +- 大批量 Excel/CSV、分数线、视频导入和异步 worker 还未完成。 +- 数据看板、分佣结算、AI 择校、主题模板市场等仍是后续商用增强项。 + +## 前后端协作建议 + +- 前端先做页面骨架和 API client,不要在页面里写死租户、地区、资源地址、商户号或 provider 密钥。 +- 每个页面先接后端已有接口;缺接口时把页面期望的字段写到 issue/TODO,再由后端补聚合接口。 +- 权限判断以后端结果为准,前端只做菜单和按钮可见性优化。 +- 旧项目只作为样式、交互和字段含义参考;长期数据模型以新 API 为准。 + diff --git a/docs/refactor/legacy-feature-gap-matrix.md b/docs/refactor/legacy-feature-gap-matrix.md new file mode 100644 index 00000000..be5f9433 --- /dev/null +++ b/docs/refactor/legacy-feature-gap-matrix.md @@ -0,0 +1,111 @@ +# 旧题库功能差距矩阵 + +更新时间:2026-06-28 + +旧项目位于 `F:\project\参考\旧题库项目`,只作为功能、样式、交互和迁移参考。新项目不再复刻 PocketBase/SQLite 的数据结构,而是以新多租户 SaaS 模型为准。 + +状态说明: + +- `已覆盖`:新后端已有对应模型和接口。 +- `部分覆盖`:已有主干,但商用体验或边界还要补。 +- `未覆盖`:需要新增后端能力。 +- `前端为主`:后端已有基础,主要由 Taro/H5 实现展示和交互。 + +## 学生端功能 + +| 旧功能/页面 | 旧项目参考 | 新后端状态 | 待补齐 | +| --- | --- | --- | --- | +| 登录/注册 | `pages/Login.tsx` | 部分覆盖 | 短信 mock/session 已有;微信小程序、微信网页、QQ、正式 JWT 未完成 | +| 选地区 | `pages/RegionSelector.tsx` | 已覆盖 | 需要前端按租户套餐和权益展示可选地区 | +| 首页/学生看板 | `pages/StudentDashboardNew.tsx` | 部分覆盖 | 品牌、Banner、公告、入口、个人统计有基础;缺完整运营动态/学习任务聚合 | +| 题库入口 | `pages/SubjectSelector.tsx`、`RegionArchitectureEditor.tsx` | 已覆盖 | 前端应改接 `content_entries/content_nodes` | +| 多级分类树 | 旧 module/subject/category 树 | 已覆盖 | 新后端支持任意深度和 `marker_type`;前端不要写死层级 | +| 顺序刷题 | `pages/Quiz.tsx` | 已覆盖 | 继续补题量限制、断点续练、更多题型渲染 | +| 随机刷题 | `pages/Quiz.tsx` | 已覆盖 | 已有 blueprint/session 快照,前端需按 mode 调用 | +| 全真模拟 | `components/AdminMockexam`、`MockExamConfigModal.tsx` | 部分覆盖 | 后端有 blueprint 基础;缺完整交卷报告、排名、复盘 | +| 错题本 | 用户 stats/错题逻辑 | 已覆盖 | 后续补错题复习计划 | +| 收藏夹 | `WordFavoritesPage.tsx`、题目收藏 | 已覆盖 | 题目和单词收藏已有 | +| 题目视频 | `VideoPlayer.tsx` | 部分覆盖 | 题目视频查询已有;缺播放签名、次数扣减、水印、防下载 | +| 背单词 | `VocabularyPage.tsx`、`VocabularyQuiz.tsx` | 部分覆盖 | 单词列表/进度/收藏/统计已有;缺完整艾宾浩斯算法、每日计划、收藏练习细节 | +| 知识手册 | `Handbook*.tsx` | 已覆盖 | 前端需做好 Markdown/公式/图片渲染和搜索体验 | +| 分数线 | `ScorelinePage.tsx` | 已覆盖 | 动态字段/趋势已有;缺批量导入和复杂筛选优化 | +| 商城/SVIP | `Store.tsx`、`SvipModal.tsx` | 部分覆盖 | 套餐/订单/权益/激活码已有;缺真实支付、优惠券抵扣 | +| 个人中心 | `Profile.tsx` | 部分覆盖 | 基本资料、权益、订单统计有;缺完整勋章、签到、学习报告 | +| 资料下载 | `QuestionExporterPublishModal.tsx` 等 | 部分覆盖 | 资源台账/签名下载已有;缺 PDF 预览、下载水印、防盗链 | +| AI 择校推荐 | 业务规划新增 | 未覆盖 | 需设计学生输入 schema、地区数据上下文、AI JSON 输出、PDF 报告 | + +## 租户后台功能 + +| 旧功能/组件 | 新后端状态 | 待补齐 | +| --- | --- | --- | +| 用户管理 | 部分覆盖 | 租户成员 API 已有;学生用户列表、批量导入、禁用/补绑/CRM 批量推送还需完善 | +| 销售/代理管理 | 部分覆盖 | referral/team/stats 有;缺分佣比例、结算单、审核、导出 | +| 班级/教师管理 | 未覆盖 | 需新增班级、学生分班、教师可见范围 | +| 数据看板 | 部分覆盖 | 表基础有;缺收益、注册、答题、活跃、套餐销量等聚合 API | +| 地区管理 | 部分覆盖 | 地区和内容入口已有;缺按 SaaS 套餐限制地区/题库授权的完整流程 | +| 品牌配置 | 已覆盖 | 需要前端做预览和主题发布体验 | +| 自定义域名 | 已覆盖 | 生产需补 DNS 校验、证书状态、回源校验 | +| 主题系统 | 部分覆盖 | 当前 theme JSON 可用;缺三套平台主题模板和素材管理 | +| 商户收款配置 | 部分覆盖 | 配置 API 有;缺真实支付 provider 和验签 | +| 登录配置 | 部分覆盖 | 配置 API 有;缺真实短信/OAuth provider 实现 | +| Banner/公告/FAQ/活动 | 已覆盖 | 前端运营后台可以接 | +| SVIP 套餐 | 已覆盖 | 后续补地区/分类/专业增项限制规则 | +| 优惠券 | 部分覆盖 | 后台配置有;前台兑换、下单抵扣待补 | +| 激活码 | 已覆盖 | 批次、生成、兑换主链路已有 | +| 勋章管理 | 部分覆盖 | 表结构有 badges/user_badges;缺后台和学生端 API | +| 题库录入 | 已覆盖 | 单题创建/更新、JSON 导入、集合/蓝图已有 | +| 题库导出 PDF/Word/JSON | 未覆盖 | 旧前端有导出组件;新后端需决定是否服务端导出或前端导出 | +| 题型分组/模拟卷配置 | 部分覆盖 | question_type_groups 表和 blueprint 有基础;后台配置体验待补 | +| 背单词维护 | 已覆盖 | 单元/单词 CRUD 和导入已有 | +| 知识手册维护 | 已覆盖 | subject/chapter/entry CRUD 和导入已有 | +| 分数线维护 | 已覆盖 | 字段/院校/专业/记录 CRUD 已有 | +| 视频维护/绑定 | 已覆盖 | video CRUD 和 question-video 绑定已有 | +| CRM 配置和队列 | 部分覆盖 | 配置/队列已有;发送 worker 待补 | +| 对象存储配置 | 部分覆盖 | 系统 env provider 已有;租户级存储策略、上传后校验待补 | + +## 平台 SaaS 后台功能 + +| 功能 | 新后端状态 | 待补齐 | +| --- | --- | --- | +| 创建/管理租户 | 已覆盖 | 平台后台页面待做 | +| SaaS 套餐 | 已覆盖 | 需要和地区/题库授权策略打通 | +| 年费/服务费账单 | 已覆盖 | 真实支付/开票/催缴流程待补 | +| 租户用量记录 | 已覆盖 | 自动采集 worker 待补 | +| 公共题库/地区题库 | 部分覆盖 | question_banks 有 source_scope;缺租户采纳、授权、版本同步 | +| 跨租户运营看板 | 部分覆盖 | overview 有基础;缺完整 BI 聚合 | +| 租户安全审计 | 部分覆盖 | audit logs 有;缺平台级审计报表 | + +## 旧功能中应重新设计的点 + +- 旧项目把很多用户状态放在 JSON 或前端逻辑里,新项目应拆到独立表或后端服务。 +- 旧树形结构只作为迁移来源,新前端应使用 `content_entries/content_nodes/question_collections/practice_blueprints`。 +- 旧资料/视频 URL 不能继续让前端直连私有资源,新项目统一走 `content_assets` 和签名 URL。 +- 旧后台的一些“隐藏入口/超管直贴 JSON”应改为 preview/import/job/issue 审计流。 +- 旧支付和激活码逻辑要统一成订单、支付事件、权益开通、幂等 webhook。 +- 旧销售追踪要升级为租户内角色权限 + 首绑保护 + 分佣结算 + CRM worker。 + +## 后端补齐优先级 + +### P0:前端联调到云端前 + +1. 正式鉴权:Supabase Auth/JWT 或服务端 session,替换迁移期请求头。 +2. 生产配置 fail-fast:默认密钥、`CORS=*`、mock SMS、平台默认 key 必须禁止。 +3. JSON body size limit:导入接口可配置更大限制,但必须有上限。 +4. 真实租户隔离测试:跨租户读写、角色越权、资源下载越权。 +5. 真实短信/微信小程序登录最小闭环。 + +### P1:商用主链路 + +1. 微信/支付宝支付和 webhook 幂等。 +2. 对象存储 PDF 预览、视频播放签名、防盗链、水印。 +3. Excel/CSV、分数线、视频批量导入。 +4. 数据看板和销售/代理分佣结算。 +5. 公共题库授权、租户采纳和版本同步。 + +### P2:增强体验 + +1. 主题模板、素材库、主题预览/发布。 +2. 班级、教师、学生分组和学习督导。 +3. AI 择校推荐和 PDF 报告。 +4. 题库导出、试卷生成、每日一练运营工具。 + diff --git a/docs/refactor/multitenant-auth-security-contract.md b/docs/refactor/multitenant-auth-security-contract.md new file mode 100644 index 00000000..a2c21546 --- /dev/null +++ b/docs/refactor/multitenant-auth-security-contract.md @@ -0,0 +1,156 @@ +# 多租户与鉴权安全契约 + +更新时间:2026-06-28 + +这个系统后续要卖给同行作为题库 SaaS,因此租户隔离、鉴权、资源权限和审计是商用红线。前端可以先按迁移期接口联调,但正式上云验收前必须完成本文件的 P0 项。 + +## 安全边界 + +| 边界 | 规则 | +| --- | --- | +| 平台超级管理员 | 可管理全部租户、SaaS 套餐、订阅、账单、用量、公共题库 | +| 租户管理员 | 只能管理自己租户的品牌、域名、成员、内容、营销、订单和 CRM | +| 租户成员 | 按角色和 permissions 访问,例如运营、教师、销售、代理 | +| 学生用户 | 只能访问自己所在租户下被授权的内容和自己的学习数据 | +| 公共题库 | 必须通过平台授权/租户采纳后才对租户可见 | +| 私有资源 | 必须通过后端权限校验后签名访问,不能前端直连对象存储 | + +## 当前迁移期状态 + +当前后端仍存在这些迁移期实现: + +- `x-tenant-id` 用于租户上下文。 +- `x-user-id` 或 body/query 的 `userId` 用于用户上下文。 +- `x-platform-admin-key` 用于平台管理员接口。 +- 本地短信 provider 可使用 `mock`。 +- 默认开发密钥存在于 `.env.example` 和 config fallback。 + +这些只允许用于本地开发和内网联调,不允许作为正式云端验收方案。 + +## P0:正式云端测试前必须完成 + +1. 正式用户鉴权 + - 使用 Supabase Auth/JWT 或服务端 session 解析可信 userId。 + - 禁止前端通过 query/body/header 指定 userId。 + - `GET /api/auth/me` 返回当前用户、租户成员、角色、权限。 + +2. 正式租户上下文 + - H5 可由域名解析租户。 + - 小程序可由 tenantCode 解析租户。 + - 后端必须校验用户是否属于该租户。 + - 跨租户请求必须返回 403 或 404。 + +3. 平台管理员鉴权 + - 替换 `x-platform-admin-key`。 + - 平台管理员也要有 JWT/session、角色、审计日志。 + +4. 生产配置 fail-fast + - `NODE_ENV=production` 时禁止默认 `AUTH_CODE_PEPPER`。 + - 禁止默认 `AUTH_SESSION_SECRET`。 + - 禁止默认 `PLATFORM_ADMIN_API_KEY`。 + - 禁止 `CORS_ORIGIN=*`。 + - 禁止 `AUTH_SMS_PROVIDER=mock`。 + +5. 请求体大小限制 + - 普通 JSON API 必须有默认上限。 + - 导入接口可以有更大上限,但必须可配置且有最大值。 + - 超限返回 413。 + +6. 租户密钥保护 + - 商户密钥、短信 secret、OAuth secret 不允许明文长期存储。 + - 生产应使用 KMS/Vault 或 envelope encryption。 + - API 只返回 `secretRef`、掩码和配置状态。 + +7. RLS 与 API 双层回归 + - 数据库 RLS 要按 `tenant_id` 拦截。 + - API SQL 必须显式带 `tenant_id`。 + - 测试必须覆盖跨租户读取、写入、下载、后台权限越权。 + +## 前端必须遵守 + +- 不信任本地缓存里的 tenantId/userId 作为安全依据。 +- 不在页面里保存或展示任何商户密钥、短信密钥、OAuth secret。 +- 不在前端硬编码对象存储 bucket、私有资源路径、商户号。 +- 不在前端自行开通会员权益;必须通过订单/支付/激活码后端流程。 +- 不允许“切换销售归属”这类破坏首绑保护的入口,除非后端提供带权限的管理接口。 +- 不在前端直接判断“这个用户能不能看某题/某视频/某资料”的最终结果;必须请求后端。 +- 切换租户、退出登录、登录新账号时,清理旧租户缓存和用户缓存。 + +## 后端接口约定 + +所有业务表查询必须满足: + +```text +where tenant_id = currentTenantId +``` + +管理类写接口必须满足: + +```text +requireTenantPermission(auth, ':') +``` + +平台类接口必须满足: + +```text +requirePlatformAdmin(auth) +``` + +资源下载必须满足: + +```text +content_assets 台账存在 +资源属于当前 tenant +资源状态允许访问 +用户权益满足 visibility/access_rules +返回短期签名 URL +``` + +支付 webhook 必须满足: + +```text +验签通过 +provider event id 幂等 +订单 tenant_id 匹配 +金额以后端订单金额为准 +事务内更新 payment/order/entitlement +记录 payment_events +``` + +## 权限点现状 + +当前默认角色: + +| 角色 | 默认权限 | +| --- | --- | +| tenant_owner | `*` | +| tenant_admin | `*` | +| tenant_operator | 内容、营销、兑换码/优惠券只读、客资/CRM 只读 | +| teacher | 内容维护 | +| sales | 兑换码、优惠券、客资 | +| agent | 兑换码/优惠券只读、本人的客资 | +| student | 无后台权限 | + +后续要补: + +- 租户自定义角色模板。 +- 菜单级、模块级、字段级权限。 +- 权限变更审计。 +- 班级/教师/学生范围权限。 + +## 上线前安全验收清单 + +- `npm audit` 为 0 高危/严重漏洞。 +- `npm run check:refactor` 通过。 +- 生产环境启动时默认密钥 fail-fast 生效。 +- 跨租户学生读取题目/订单/资料返回拒绝。 +- 销售只能查看自己权限范围内客资。 +- 代理不能查看其他代理客资。 +- 教师不能修改租户商户密钥。 +- 学生不能访问租户后台接口。 +- 未开通权益不能下载 SVIP 资料或播放会员视频。 +- 支付 webhook 重放不会重复开通权益。 +- 激活码并发兑换只能成功一次。 +- 对象存储签名 URL 有短 TTL。 +- 后台关键操作写入 audit log。 + diff --git a/docs/refactor/taro-frontend-integration.md b/docs/refactor/taro-frontend-integration.md new file mode 100644 index 00000000..206eb00c --- /dev/null +++ b/docs/refactor/taro-frontend-integration.md @@ -0,0 +1,202 @@ +# Taro 前端对接指南 + +更新时间:2026-06-28 + +目标:用一套 Taro 工程同时服务微信小程序和 H5 Web 题库,统一调用 `apps/api`,并支持多租户、品牌主题、地区题库、会员权益、销售追踪和对象存储资源。 + +建议新建: + +```text +F:\project\apps\taro +``` + +旧前端参考: + +```text +F:\project\参考\旧题库项目\src +``` + +## 启动流程 + +### H5 + +1. 从 `window.location.host` 获取当前域名。 +2. 调用 `GET /api/tenant/resolve?host=`。 +3. 保存 `tenant.id`、`tenant.slug`、`branding`、`features`、`publicConfig`。 +4. 初始化主题、Logo、页面标题、功能开关。 +5. 检查本地 session token,调用 `GET /api/auth/me`。 +6. 如果未登录,进入登录页;如果已登录,加载个人中心和首页数据。 + +### 微信小程序 + +1. 从编译环境或小程序启动参数读取 `tenantCode`。 +2. 推广码、销售码、分享码从 `options` 或 `scene` 中解析。 +3. 调用 `GET /api/tenant/resolve?tenantCode=`。 +4. 如存在 referral 参数,先调用 `/api/referral/resolve` 和 `/api/referral/track-event`。 +5. 登录后再调用 `/api/referral/bind` 完成首绑保护。 + +## 请求封装 + +前端应封装一个统一 API client,所有页面禁止直接散写 `Taro.request`。 + +迁移期请求头: + +```text +Authorization: Bearer +x-tenant-id: +x-user-id: +``` + +生产目标: + +```text +Authorization: Bearer +``` + +生产后不应再由前端传 `x-user-id`。租户可以由可信 JWT claim、服务端 session、域名解析结果共同确定;前端传入的租户参数只能作为路由/展示上下文,不能作为安全依据。 + +统一错误处理: + +| HTTP | 前端动作 | +| --- | --- | +| 400 | 展示表单错误或参数错误 | +| 401 | 清 session,跳登录 | +| 403 | 展示无权限或会员升级 | +| 404 | 展示空状态 | +| 409 | 展示业务冲突,例如激活码已用 | +| 413 | 提示上传/导入文件过大 | +| 429 | 倒计时重试,例如短信冷却 | +| 500 | 展示系统异常并上报日志 | + +## 全局状态建议 + +| Store | 内容 | +| --- | --- | +| tenantStore | tenant、branding、theme、features、publicConfig | +| authStore | session、user、roles、permissions、loginState | +| regionStore | 当前地区、可选地区、地区权益 | +| catalogStore | content entries、nodes、collections、blueprints | +| entitlementStore | SVIP 权益、视频权益、资料下载权益 | +| referralStore | inviteCode、referrer、scene、bindState | +| uiStore | 当前主题、tab、loading、toast、modal | + +注意缓存必须带租户维度,例如: + +```text +tenant::catalog:entries +tenant::profile +tenant::theme +``` + +切换租户或切换小程序环境时必须清理旧租户缓存。 + +## 页面/API 映射 + +| 页面 | 主要接口 | +| --- | --- | +| 启动页 | `GET /api/tenant/resolve` | +| 登录页 | `POST /api/auth/sms/send`、`POST /api/auth/sms/verify`、后续微信/QQ provider | +| 首页 | `/api/catalog/content-entries`、`/api/catalog/banners`、`/api/catalog/announcements`、`/api/profile/me` | +| 选地区 | `/api/catalog/regions`、`/api/commerce/entitlements/check` | +| 题库入口 | `/api/catalog/content-entries` | +| 分类树 | `/api/catalog/content-nodes?entryId=...&parentId=root` | +| 题目列表 | `/api/catalog/question-collections`、`/api/catalog/question-collections/questions` | +| 开始练习 | `POST /api/learning/practice-sessions` | +| 提交答案 | `POST /api/learning/answers` | +| 错题本 | `GET /api/learning/wrong-questions`、`POST /api/learning/wrong-questions/resolve` | +| 收藏夹 | `GET/POST /api/learning/favorites/questions` | +| 题目视频 | `GET /api/questions/{questionId}/videos`、`POST /api/questions/videos/batch` | +| 背单词 | `/api/catalog/vocabulary-units`、`/api/catalog/vocabulary-words` | +| 单词进度 | `/api/learning/vocabulary/progress`、`/api/learning/vocabulary/stats` | +| 单词收藏 | `/api/learning/vocabulary/favorites` | +| 知识手册 | `/api/catalog/handbook-subjects`、`handbook-chapters`、`handbook-entries` | +| 分数线 | `/api/scoreline/fields`、`schools`、`majors`、`records`、`trend`、`years` | +| 资料下载 | `/api/catalog/assets`、`/api/catalog/assets/download` | +| 商城 | `/api/catalog/svip-plans`、`POST /api/commerce/orders` | +| 订单/权益 | `/api/commerce/orders`、`/api/commerce/entitlements` | +| 激活码兑换 | `POST /api/commerce/activation-codes/redeem` | +| 个人中心 | `GET/PATCH /api/profile/me` | +| 销售分享 | `/api/referral/resolve`、`track-event`、`bind` | + +## 题库新模型接入方式 + +旧项目常按“地区 -> 科目 -> 章节/试卷”固定层级处理。新项目不要写死层级,按下面模型渲染: + +```text +content_entries + -> content_nodes 任意深度分类树 + -> question_collections 题目列表/试卷/章节/题型集合 + -> practice_blueprints 顺序/随机/全真模拟规则 +``` + +前端建议: + +- `entryType=question_practice` 渲染为刷题入口。 +- `entryType=vocabulary` 渲染为背单词入口。 +- `entryType=handbook` 渲染为知识手册入口。 +- `markerType=school` 或 `markerType=exam_track` 可作为学生目标院校/专业意向采集。 +- 不同地区节点层级可以不同,页面组件必须支持递归树和面包屑。 + +## 多租户前端优化 + +- Logo、标题、主题色、客服信息全部来自 `tenant/resolve`。 +- 功能开关控制菜单显示,但接口权限仍以后端为准。 +- 私有图片、PDF、视频不要直接拼 URL,一律通过后端签名。 +- 支付渠道从后端返回或租户配置读取,不在页面硬编码。 +- 小程序分享路径必须带 tenantCode 和 referral code。 +- 用户首绑归属由后端保护,前端不要提供“换绑销售”入口。 +- 管理后台菜单按 `GET /api/tenant-admin/permissions` 和用户权限渲染。 +- H5 自定义域名下要注意缓存隔离,不能把 A 租户主题缓存用到 B 租户。 + +## 第一阶段页面建议 + +1. `pages/bootstrap/index` + - 租户解析、主题初始化、登录态恢复。 +2. `pages/login/index` + - 先接短信登录;后续接微信小程序登录。 +3. `pages/home/index` + - Banner、公告、题库入口、会员入口、资料入口。 +4. `pages/region/index` + - 地区选择和权益提示。 +5. `pages/catalog/index` + - entry/node/collection/blueprint 通用导航。 +6. `pages/practice/index` + - 刷题、答题、解析、错题、收藏。 +7. `pages/vocabulary/index` + - 单词单元、学习、收藏。 +8. `pages/handbook/index` + - 手册目录和阅读。 +9. `pages/scoreline/index` + - 动态字段筛选和趋势。 +10. `pages/profile/index` + - 会员、订单、激活码、学习数据。 + +## 租户后台前端建议 + +租户后台可以先做 H5 管理台,也可以后续使用 Taro H5 复用部分组件。优先页面: + +- 概览:`/api/tenant-admin/overview` +- 品牌/主题/域名/公开设置 +- 支付账户/登录 provider/密钥引用 +- 用户与成员权限 +- 内容入口/分类树/题目集合/练习蓝图 +- 题目/单词/知识手册/分数线/视频维护 +- JSON 导入 preview/import/issues +- Banner/FAQ/公告/激活码/优惠券 +- 销售/代理/CRM 队列 + +租户后台不应在前端自行决定权限;隐藏菜单只是体验优化,接口仍会校验权限。 + +## 联调顺序 + +1. 启动页和租户解析。 +2. 短信登录和 `auth/me`。 +3. 首页、地区、内容入口、题库树。 +4. 练习 session、答题、错题、收藏。 +5. 背单词、知识手册、分数线。 +6. 会员套餐、订单、激活码。 +7. 资料下载、视频解析。 +8. 销售追踪和分享链路。 +9. 租户后台内容维护和导入。 +10. 正式鉴权、真实支付、对象存储生产联调。 +