forked from wangziqi/gongxue-base
216 lines
8.8 KiB
Markdown
216 lines
8.8 KiB
Markdown
# AI 开发守则与安全基线
|
||
|
||
更新时间:2026-06-28
|
||
|
||
这份文档是后续 AI、后端、前端、运维共同遵守的最高优先级开发规范。项目可以逐步演进,但不能破坏这里定义的安全边界和架构方向。
|
||
|
||
## 总原则
|
||
|
||
本项目采用 Supabase-first 架构:
|
||
|
||
- PostgreSQL/Supabase 是数据和权限事实来源。
|
||
- Supabase Auth/JWT 是用户身份的主方向。
|
||
- RLS、视图、函数、触发器、约束和索引优先承担数据层安全。
|
||
- `apps/api`、Edge Functions、worker 承担复杂业务命令、密钥、第三方 provider、异步任务和审计。
|
||
- Taro/H5/小程序可以使用 Supabase client,但不能直接改写复杂业务表。
|
||
|
||
一句话:优先使用 Supabase 原生能力,但不要把业务规则散落到前端页面里。
|
||
|
||
## 新功能落位判断树
|
||
|
||
新增功能时按下面顺序判断:
|
||
|
||
1. 只是公开、低风险、只读数据?
|
||
- 优先使用 view + RLS + Supabase Data API。
|
||
- 例如公开 Banner、公开 FAQ、公开主题资源。
|
||
|
||
2. 是当前用户自己的简单数据,且没有复杂副作用?
|
||
- 可以考虑 table/view + RLS。
|
||
- 必须有跨租户测试、越权测试、最小 grant。
|
||
- 例如个人公开资料读取、只读学习统计快照。
|
||
|
||
3. 是一个跨表业务动作,但全部在数据库内可安全完成?
|
||
- 优先 Postgres function/RPC。
|
||
- 必须 `security definer`/`security invoker` 选择清楚,函数内部显式校验 tenant/user/role。
|
||
- 例如激活码原子兑换、简单计数扣减、幂等状态流转。
|
||
|
||
4. 需要第三方密钥、HTTP 调用、webhook、文件签名、AI、支付、短信、微信/QQ?
|
||
- 使用 Edge Function、`apps/api` 或 worker。
|
||
- 密钥只在服务端环境变量/KMS/Vault。
|
||
|
||
5. 需要长任务、重试、队列、定时统计、导入后校验?
|
||
- 使用 worker。
|
||
- API 只负责提交 job 和查询 job 状态。
|
||
|
||
## 严禁事项
|
||
|
||
- 严禁在 Taro/H5/小程序中放入 Supabase secret key、service role key、数据库连接串、支付私钥、短信密钥、对象存储密钥。
|
||
- 严禁前端直接写订单、支付、权益、激活码使用状态、租户密钥、平台账单、CRM 队列、内容导入结果。
|
||
- 严禁为了快速开发关闭 RLS 或写宽泛 policy。
|
||
- 严禁只靠前端隐藏按钮实现权限控制。
|
||
- 严禁绕过 `content_assets` 台账直接拼接私有 OSS/COS/Supabase Storage URL。
|
||
- 严禁在日志、导入 issue、审计日志中写入明文验证码、商户密钥、OAuth secret、支付私钥。
|
||
- 严禁把旧 PocketBase 字段结构作为新系统长期事实来源。
|
||
- 严禁为学生头像新增上传链路、对象存储签名、第三方头像落库或后台批量导入字段;学生头像只允许 `avatarPreset=male/female` 默认资源,租户后台学生接口也不能写头像 URL 或平台主角色字段。
|
||
- 严禁在学生端默认请求或展示排行榜;排行榜接口只作为租户显式开启后的活动能力,默认学习激励以后台配置的勋章自动发放为主。
|
||
- 严禁新增 Taro 页面后不注册路由、不更新启动页/静态烟测入口或不更新前端交接清单;页面变更后必须运行 `node scripts/taro-route-contract-test.js`,确保 `app.config.ts`、`pages/**/index.tsx`、启动页跳转和交接文档一致。
|
||
- 严禁在 Taro service 中调用未注册的后端 API、写错 HTTP method 或绕过统一 `/api` 命名空间;API service 变更后必须运行 `node scripts/taro-api-contract-test.js`,动态路由必须在脚本 allowlist 中显式说明后端落点。
|
||
- 严禁在重做页面样式时删除学生刷题/会员订单/错题收藏、租户学生运营/内容导入/营销财务/品牌权限、平台租户/账务/公共题库/员工权限这些关键角色旅程的服务调用或跳转;相关页面变更后必须运行 `node scripts/taro-persona-contract-test.js`,真实业务确实改名时要同步更新脚本、接口文档和前端交接清单。
|
||
|
||
## Supabase 直连表的准入条件
|
||
|
||
任何前端直连 Supabase table/view 之前,必须满足:
|
||
|
||
- 已启用 RLS。
|
||
- 已有最小权限 policy。
|
||
- 不暴露跨租户数据。
|
||
- 不暴露未开通权益的数据。
|
||
- 不包含密钥、手机号批量列表、支付流水、后台配置等敏感信息。
|
||
- 已有跨租户测试。
|
||
- 已有角色越权测试。
|
||
- 已有索引和分页限制。
|
||
- 读写语义不会绕过业务审计。
|
||
|
||
不满足任一条件,就不能前端直连,必须走 RPC、Edge Function、`apps/api` 或 worker。
|
||
|
||
## RPC/数据库函数规范
|
||
|
||
适合 RPC:
|
||
|
||
- 原子事务。
|
||
- 简短业务命令。
|
||
- 强一致状态变化。
|
||
- 不需要外部 HTTP provider。
|
||
- 可以完全在数据库内校验权限。
|
||
|
||
RPC 必须:
|
||
|
||
- 参数包含或可推导 tenant 上下文。
|
||
- 使用 `auth.uid()`、JWT claim 或服务端传入的可信 userId。
|
||
- 函数内显式校验 membership/role/permission。
|
||
- 返回稳定、前端友好的 JSON。
|
||
- 对并发场景使用唯一约束、`for update`、幂等键或事务。
|
||
- 写关键操作审计。
|
||
|
||
不适合 RPC:
|
||
|
||
- 支付平台验签。
|
||
- 发送短信。
|
||
- 微信/QQ OAuth 换取用户信息。
|
||
- CRM webhook 推送。
|
||
- OSS/COS 私有签名。
|
||
- 大文件处理。
|
||
- AI 报告生成。
|
||
|
||
这些应放在 Edge Function、`apps/api` 或 worker。
|
||
|
||
## `apps/api` 使用原则
|
||
|
||
`apps/api` 不是为了替代 Supabase,而是作为业务命令层:
|
||
|
||
- 验证 Supabase JWT/session。
|
||
- 解析租户。
|
||
- 聚合多表数据。
|
||
- 校验角色和 permissions。
|
||
- 调用 RPC 或执行事务。
|
||
- 调用第三方 provider。
|
||
- 处理 webhook 验签和幂等。
|
||
- 签发私有资源 URL。
|
||
- 提交/查询异步 job。
|
||
- 写审计日志。
|
||
|
||
后续如果某个模块更适合 Edge Functions,可以迁移过去,但必须保持统一的鉴权、审计、错误码和测试标准。
|
||
|
||
## 多租户安全规范
|
||
|
||
每个业务表默认必须有:
|
||
|
||
- `tenant_id`
|
||
- 必要唯一约束包含 `tenant_id`
|
||
- 必要索引包含 `tenant_id`
|
||
- RLS policy
|
||
- API/RPC SQL 显式 tenant 过滤
|
||
|
||
例外情况必须在 migration 中注释说明,例如平台全局字典、公开主题模板。
|
||
|
||
公共题库也不能天然跨租户可见。必须通过授权、采纳、复制或订阅关系授予租户使用权。
|
||
|
||
## 权限规范
|
||
|
||
权限判断顺序:
|
||
|
||
1. 平台超级管理员。
|
||
2. 租户 membership。
|
||
3. 租户角色默认权限。
|
||
4. 租户自定义 permissions 覆盖。
|
||
5. 资源范围权限,例如本人客资、班级学生、地区授权、题库授权。
|
||
6. 权益权限,例如 SVIP、视频次数、资料下载权限。
|
||
|
||
前端只负责 UI 可见性,后端/RPC/RLS 才是最终裁决。
|
||
|
||
## 导入与迁移规范
|
||
|
||
所有题目、单词、知识手册、分数线、视频等批量导入必须走:
|
||
|
||
```text
|
||
preview -> job -> items -> issues -> import -> audit -> validate
|
||
```
|
||
|
||
CSV/Excel 导入属于后端规范化能力,`.xlsx` 解析统一走 `read-excel-file`。不要把 `exceljs` 重新加入生产运行时;确需替换解析库时,必须同时证明 `npm run audit:runtime` 通过,并用 API 集成测试覆盖多 Sheet 分数线、题目、单词、知识手册和视频导入。
|
||
|
||
导入不得直接从前端写正式业务表。迁移脚本若因一次性内控需要直写数据库,必须:
|
||
|
||
- 保留原始 payload。
|
||
- 生成迁移报告。
|
||
- 跑 `pb:import:validate`。
|
||
- 跑 `check:refactor`。
|
||
- 人工抽样验收。
|
||
|
||
## 支付与权益规范
|
||
|
||
支付相关必须满足:
|
||
|
||
- 订单金额以后端套餐/商品价格为准。
|
||
- 前端传来的金额只能作为展示或校验参考。
|
||
- webhook 必须验签。
|
||
- webhook 必须有 provider event id 幂等。
|
||
- 支付成功、权益开通必须在事务中完成。
|
||
- 激活码兑换必须防并发。
|
||
- 退款/撤销必须生成可审计事件。
|
||
|
||
## 对象存储规范
|
||
|
||
- 公开品牌图可以放公开 bucket/CDN。
|
||
- 私有 PDF、资料、视频必须进入 `content_assets`。
|
||
- 下载/播放必须由后端或 Edge Function 校验权限后签发短期 URL。
|
||
- 上传后必须校验对象存在性、size、mime、hash。
|
||
- 视频应补防盗链、水印、播放日志和次数扣减。
|
||
|
||
## 测试与提交规范
|
||
|
||
涉及业务逻辑、安全边界、权限、支付、导入、资源访问的改动,提交前至少运行:
|
||
|
||
```bash
|
||
npm run check:refactor
|
||
```
|
||
|
||
新增直连 Supabase 表、RPC、RLS policy、权限点时,必须增加或更新测试覆盖:
|
||
|
||
- 同租户允许。
|
||
- 跨租户拒绝。
|
||
- 低权限拒绝。
|
||
- 未登录拒绝。
|
||
- 并发/幂等。
|
||
|
||
## 给后续 AI 的开发提示
|
||
|
||
实现代码前先查:
|
||
|
||
1. `docs/refactor/ai-development-guardrails.md`
|
||
2. `docs/refactor/supabase-frontend-access-strategy.md`
|
||
3. `docs/refactor/multitenant-auth-security-contract.md`
|
||
4. `docs/refactor/backend-capability-status.md`
|
||
5. `docs/refactor/legacy-feature-gap-matrix.md`
|
||
|
||
如果需求与这些文档冲突,先更新架构文档并说明原因,再改代码。
|