Files
gongxue-base/docs/refactor/supabase-frontend-access-strategy.md

162 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Supabase 前端访问策略
更新时间2026-06-28
这份文档用于回答一个关键架构问题Taro/H5/小程序前端到底应该直接调用 Supabase还是调用我们自己的 `apps/api` 后端?
结论采用“Supabase Auth/JWT + 业务 API 优先 + 有边界的 Supabase Client 直连”的混合架构。
## 官方依据
Supabase 官方文档的核心原则:
- 前端可以使用 Supabase client/Data API 访问数据,但前提是启用 RLS并且只授予最小权限。
- https://supabase.com/docs/guides/database/secure-data
- https://supabase.com/docs/guides/database/postgres/row-level-security
- 前端应使用 publishable keypublishable key 可以暴露,但必须配合 RLS 和最小权限。
- https://supabase.com/docs/guides/database/secure-data
- https://supabase.com/docs/guides/getting-started/api-keys
- secret key / service role key 永远不能暴露在前端,因为它们会绕过 RLS。
- https://supabase.com/docs/guides/getting-started/api-keys
- 复杂服务端逻辑、第三方 API、webhook、密钥和数据库连接应放在服务端例如 Edge Functions、worker 或自有后端。
- https://supabase.com/docs/guides/functions
- Supabase Auth 使用 JWTJWT 可以和 RLS、服务端鉴权结合。
- https://supabase.com/docs/guides/auth
- https://supabase.com/docs/guides/auth/jwts
## 对本项目的判断
我们的系统不是简单 CRUD 应用,而是面向同行销售的题库 SaaS
- 多租户隔离。
- 平台超级管理员和租户管理员双后台。
- 租户内自定义角色、运营、教师、销售、代理、学生。
- 订单、支付、激活码、权益、视频次数。
- 题库导入、内容审核、资源台账。
- 阿里云 OSS、腾讯 COS、Supabase Storage 混合对象存储。
- CRM 推送、销售首绑、分佣结算。
- 未来还要接微信/QQ 登录、微信/支付宝支付、AI 报告。
这些都包含复杂业务规则、密钥、幂等、审计和跨表事务。因此不能让 Taro 前端直接写业务表来替代后端。
## 推荐架构
```text
Taro/H5/小程序
├─ Supabase client
│ ├─ Auth session/JWT
│ ├─ 可选Realtime
│ └─ 可选:严格 RLS 下的低风险只读数据
└─ apps/api 业务 API
├─ 校验 Supabase JWT/session
├─ 解析 tenant
├─ 校验角色和 permissions
├─ 执行业务事务
├─ 写审计日志
├─ 签发对象存储 URL
└─ 调用支付/短信/微信/QQ/CRM/AI provider
```
`apps/api` 可以部署为我们自己的 Node.js API也可以在部分云原生场景下拆为 Supabase Edge Functions。对当前项目而言保留 `apps/api` 更适合复杂业务、国内 provider、自托管和后续 worker。
## 前端直连 Supabase 的适用范围
| 能力 | 是否建议前端直连 Supabase | 说明 |
| --- | --- | --- |
| Supabase Auth session | 建议 | H5 可直接用 `@supabase/supabase-js`;小程序需先验证运行时兼容性 |
| 获取当前用户 JWT | 建议 | API 请求统一带 `Authorization: Bearer <access_token>` |
| 低风险公开只读数据 | 可选 | 仅限 RLS、grant、索引都成熟后当前默认仍走 `apps/api` |
| Realtime 通知 | 可选 | 非敏感通知、学习状态刷新可考虑;后台敏感队列不建议前端订阅 |
| Public Storage 公开资源 | 可选 | 真正公开的 Logo、主题图可直连 CDN/公开 bucket |
| 私有资料/PDF/视频 | 不建议 | 必须通过 `content_assets` 权限校验和后端签名 |
| 学习记录/答题/错题/收藏 | 不建议 | 涉及权益、统计、审计、题目快照,应走 API |
| 订单/支付/激活码/优惠券 | 禁止 | 必须走后端事务、验签和幂等 |
| 租户后台配置 | 禁止 | 涉及权限、密钥、审计 |
| 内容导入/题库维护 | 禁止 | 必须走 preview/import/job/issues 管线 |
| 平台超级后台 | 禁止 | 必须走平台管理员鉴权和审计 |
## Taro 运行时建议
Taro 要同时支持 H5 和微信小程序。Supabase 官方 JavaScript client 是通用 JS SDK并提供 browser、React Native、自定义 fetch/storage 等配置方式,但微信小程序环境不等同于标准浏览器。
因此建议:
1. H5 端优先使用 `@supabase/supabase-js` 管理 Auth session。
2. 微信小程序端先做兼容性验证:
- `fetch` 或 request adapter。
- storage adapter。
- URL polyfill。
- token auto refresh。
3. 如果小程序端 `supabase-js` 兼容成本高,则小程序只调用 `apps/api/auth/*`
- 前端把微信 `code` 或手机号验证码发给后端。
- 后端调用 Supabase Auth/Admin 或自有 session 逻辑换取可信 session。
- 前端保存后端返回的 access token/session。
4. 无论 H5 还是小程序,业务数据默认调用 `apps/api`,不直接写 Supabase 表。
## 推荐前端环境变量
只允许出现在前端构建中的变量:
```text
TARO_APP_API_BASE_URL=https://api.example.com
TARO_APP_SUPABASE_URL=https://<project-ref>.supabase.co
TARO_APP_SUPABASE_PUBLISHABLE_KEY=sb_publishable_xxx
```
禁止出现在前端:
```text
SUPABASE_SECRET_KEY
SUPABASE_SERVICE_ROLE_KEY
DATABASE_URL
ALIYUN_OSS_ACCESS_KEY_SECRET
TENCENT_COS_SECRET_KEY
WECHAT_PAY_PRIVATE_KEY
ALIPAY_APP_PRIVATE_KEY
AUTH_SESSION_SECRET
PLATFORM_ADMIN_API_KEY
```
## API 请求目标形态
当前迁移期:
```text
Authorization: Bearer <tk_session>
x-tenant-id: <tenantId>
x-user-id: <userId>
```
生产目标:
```text
Authorization: Bearer <supabase_access_token_or_server_session>
```
生产时后端负责:
- 验证 JWT。
- 从 JWT/session 获取 userId。
- 根据 host/tenantCode/JWT claims 解析 tenant。
- 校验用户属于该租户。
- 校验角色和权限。
- 执行业务逻辑。
前端不再传 `x-user-id`,也不能靠传 `tenantId` 获得跨租户数据。
## 对后续 AI/开发者的硬性约束
- 不要把 `apps/api` 删除或绕过。
- 不要让 Taro 直接写订单、支付、权益、内容、租户配置、CRM、导入相关表。
- 不要把 service role/secret key 放进 Taro。
- 不要为了少写接口而放宽 RLS。
- 新增前端直连 Supabase 表之前,必须先补:
- 明确 RLS policy。
- 最小 grant。
- 跨租户测试。
- 权限测试。
- 性能索引。
- 若某个功能需要密钥、跨表事务、webhook、审计、幂等或第三方 provider一律放到 `apps/api` 或 worker/Edge Function。