# SaaS 题库产品边界与后续接口路线

本文档定义平台端、租户端、学生端的目标边界，以及下一阶段接口开发顺序。当前 ASP.NET Core 后端是实现基线；旧 NestJS 和 `tiki-web` 只用于核对业务行为，yudao 只用于参考套餐、商城、支付和后台运营的模块划分。

## 当前判断

现有后端已经具备继续开发的基础：Host 租户解析、强租户隔离、共享与私有题库、RBAC、Provider 解耦、租户前端运行时配置、学生练习闭环、交易基础和 Worker 基座均已落地。

第九阶段已经完成 SaaS 产品与交付闭环。当前主要缺口是：

- 教师发布作业、考试、批阅和查看班级结果的教学闭环。
- Provider 自助配置、公共题库运营和高流量查询读模型仍需完善。

## 三端边界

### 平台端

平台端是 SaaS 控制面，负责：

- 租户、租户 Owner、状态、域名和生命周期。
- SaaS 业务模块、套餐、附加包、价格和额度。
- 租户订阅、SaaS 订单、支付、退款、账单、发票、催缴和用量。
- 平台员工、平台角色、平台权限、审计和告警。
- 公共题库、公共分类、题目版本、发布和反馈质量运营。
- 平台自身的收款 Provider，不使用租户配置的学生商城支付账号。

### 租户端

租户端是机构控制面，负责：

- 员工、自定义角色、权限、班级、学生和数据范围。
- 私有题库、公共题库消费、分类扩展、组卷、导入和导出。
- 作业、考试、每日一练、批阅和教学报告。
- 品牌、主题、导航、首页模块和自定义域名。
- 身份、SMS、对象存储、学生商城支付、通知和 AI Provider。
- 学生商品、会员、优惠券、激活码、积分、CRM、推广和分佣。
- 本租户 SaaS 订阅、账单、用量、续费和升级。

### 学生端

学生端是租户域名下的数据面，负责：

- 根据 Host 获取租户品牌、功能、导航和允许的登录方式。
- 登录、绑定、个人资料和通知。
- 题库、练习、考试、作业、错题、收藏和学习报告。
- 词汇、知识手册、视频、分数线等可选内容模块。
- 租户自己的学生商城、订单、支付、优惠券、积分和权益。

## 套餐能力与权限分层

不能用一套“模块”同时表达套餐、权限和菜单。目标模型固定为：

| 概念 | 用途 |
| --- | --- |
| `SaaSFeature` | 平台可销售的业务能力 |
| `SaasOfferingVersionFeature` | 不可变套餐版本包含哪些业务能力 |
| `SaasOfferingVersionLimit` | 套餐版本的员工、学生、题目、存储、导出和 AI 额度 |
| `PermissionModule` | 后台权限页面的业务分组 |
| `BackendPermission` | `view/create/update/import/export/approve/retry` 等操作权限 |
| `BackendMenu` | 根据有效权限生成的前端导航，不作为鉴权依据 |

建议的可售卖能力包括：

- `question_bank.private`
- `learning.practice`
- `learning.assignment`
- `learning.exam`
- `content.vocabulary`
- `content.handbook`
- `content.video`
- `content.scoreline`
- `marketing.site_content`
- `student.management`
- `commerce.student_store`
- `crm.followup`
- `growth.referral_commission`
- `ai.teacher_assistant`

身份安全、角色管理、账务中心和续费入口属于核心能力。即使套餐过期，也不能阻止租户查看账单、配置管理员或完成续费。

每次受保护的业务请求必须同时满足：

```text
租户有效
+ 订阅状态允许当前读写操作
+ 套餐或附加包包含业务能力
+ 未超过对应额度
+ 当前角色具有操作权限
+ DataScope 允许访问目标数据
```

## 双交易域

平台 SaaS 商城和租户学生商城必须是两个独立边界。

### PlatformBilling

平台向租户收费，包含：

- SaaS 套餐、附加包和报价。
- SaaS 订单、支付、退款、订阅、账单和发票。
- 平台收款 Provider 和平台支付回调。
- 租户用量、超额计费、额度预警和催缴。

### TenantCommerce

租户向学生收费，包含：

- SVIP、课程资料和其他学生商品。
- 学生订单、支付、退款、优惠券、激活码和权益。
- 当前租户配置的支付 Provider 和回调。

两类订单、支付账号、回调地址、审计和对账不得共用业务表或服务。

## 已完成的 SaaS 商城与交付接口

### 平台 SaaS 商城

- 平台模块、额度定义、基础套餐、附加包和不可变版本统一在 `/api/platform-admin/saas/**`。
- 租户目录、报价、下单、支付、订阅变更、续费、取消、用量和发票统一在 `/api/tenant-billing/**`。
- 人工、微信和支付宝平台收款使用平台主体 Provider，订单和回调与学生商城分离。
- `/api/tenant-onboarding/status` 汇总 Owner、订阅、域名、登录方式、Provider 和前端发布状态。

租户自助账务接口建议统一在 `/api/tenant-billing/**`：

```text
GET  /api/tenant-billing/catalog
POST /api/tenant-billing/quotes
POST /api/tenant-billing/orders
POST /api/tenant-billing/payments
GET  /api/tenant-billing/orders/{orderNo}
GET  /api/tenant-billing/subscription
POST /api/tenant-billing/subscription/change
POST /api/tenant-billing/subscription/renew
POST /api/tenant-billing/subscription/cancel
GET  /api/tenant-billing/usage
GET  /api/tenant-billing/invoices
```

### Provider 自助管理

统一使用 `TenantExternalProvider + TenantSecret`，补齐：

```text
GET  /api/tenant-admin/providers
PUT  /api/tenant-admin/providers
POST /api/tenant-admin/providers/test
POST /api/tenant-admin/providers/activate
POST /api/tenant-admin/providers/disable
PUT  /api/tenant-admin/providers/secrets
POST /api/tenant-admin/providers/secrets/rotate
```

运行时 bootstrap 需要增加脱敏的登录方式配置，不能返回 SecretRef、密钥或第三方内部配置。

### 教师教学闭环

- 作业、考试、每日一练的创建和发布。
- 发布目标：班级、学生组、指定学生。
- 开始时间、截止时间、限时、补交和自动交卷规则。
- 学生答题草稿、断点续答和最终提交。
- 客观题自动批改，主观题教师批阅、复核和评语。
- 完成率、成绩分布、薄弱知识点和学生明细。
- 试卷、成绩、每日一练和战报导出。

现有 `PracticeBlueprint` 和 `PracticeSession` 可以作为题目装配及作答底座，但不能代替教师发布对象和班级任务状态。

### 平台公共题库运营

- 公共题库和公共分类主干管理。
- 题目草稿、审核、发布、撤回和版本对比。
- 重复题检测、反馈汇总和人工复核。
- 使用量、错误率、反馈率和版本采用情况。
- 已发布旧版本禁止物理删除。

### 查询性能和读模型

- 普通列表采用游标分页和稳定排序，禁止默认返回大集合。
- 题目、院校和知识点搜索优先使用 PostgreSQL trigram/全文索引。
- 首页、排行榜和运营看板使用聚合表或异步投影。
- 公共目录和 runtime bootstrap 使用 Redis 缓存并主动失效。
- 导入、导出、统计、资源扫描和对账进入 Worker。
- 使用 OpenTelemetry 观测慢查询、接口耗时、缓存命中和 Worker 延迟。

## 实施顺序

### 9A～9C：已完成

- `SaasFeature`、`PermissionModule`、`BackendPermission`、`BackendMenu` 已分层。
- `SaasOfferingVersion` 发布后由 Application 和 PostgreSQL guard 双重禁止修改。
- `IFeatureAccessService` 统一处理租户、订阅、Feature、覆盖、额度与权限过滤。
- PlatformBilling 与 TenantCommerce 使用独立订单、支付、回调和 Provider 配置。
- 平台创建租户及 Owner 后，租户可完成购买、开通和 onboarding。

### 9D：教师教学与考试

- 作业、考试、班级发布、批阅和教学报告。
- 智能组卷、每日一练、PDF 命题和战报持久化。
- 导出任务通过 Worker 和对象存储交付。

### 9E：学生端与性能治理

- runtime 登录选项、手机号绑定和找回密码。
- 作业/考试中心、断点续答和报告。
- 根据产品决定是否迁移备考时间线和择校功能。
- 完成分页、索引、缓存、聚合投影和性能基线测试。

### 9F：AI 独立阶段

- 面向租户教师的基础对话和后续 Function Call。
- AI 题目反馈审核，只输出建议和人工复核标记。
- Semantic Kernel 仅存在于 Infrastructure。
- 租户 API Key 保存到 `TenantSecret`。
- AI 调用量、成本和额度进入 SaaS 计量体系。

## 验收原则

- 套餐未包含的功能不能分配权限、不能显示菜单、不能调用 API、不能由 Worker 绕过执行。
- 平台角色、租户角色和学生身份不能跨 realm 使用。
- 租户 A 不能读取或修改租户 B 的配置、学生、题库、订单和 Provider。
- 平台 SaaS 支付与租户学生支付使用不同配置、订单域和回调链路。
- 套餐过期后业务写入受限，但账务、续费、安全和历史数据仍可访问。
- 高风险操作、支付状态变化、订阅变化和 Provider 变化都有审计记录。
- 关键查询在接近生产的数据量下验证执行计划、分页稳定性和响应时间。

## 参考边界

- 旧 NestJS：核对已有接口语义、状态机和异常行为，不要求保留旧 URL。
- `tiki-web`：参考已实际使用的刷题、词汇、手册、商城、营销、教研和运营功能，不复制 PocketBase 查询方式。
- yudao：参考租户套餐、商城订单、支付、退款、权限和审计的模块拆分，不照搬菜单 ID 套餐模型或 Java 运行时。
