forked from wangziqi/gongxue-base
feat: add taro h5 runtime deployment config
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
- `docs/refactor/legacy-feature-gap-matrix.md`:对照旧题库功能的新后端差距矩阵。
|
||||
- `docs/refactor/supabase-frontend-access-strategy.md`:Supabase 官方推荐能力与本项目业务 API 边界。
|
||||
- `docs/refactor/taro-frontend-integration.md`:Taro/H5/小程序启动、请求封装、页面/API 映射。
|
||||
- `docs/refactor/taro-h5-deployment.md`:Taro H5 三域名部署、运行时配置、Nginx、CSP、缓存和 CORS 边界。
|
||||
- `docs/refactor/multitenant-auth-security-contract.md`:多租户隔离、鉴权、权限和资源安全红线。
|
||||
|
||||
下一步优先级:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# SaaS 蓝图覆盖矩阵
|
||||
|
||||
更新时间:2026-06-29
|
||||
更新时间:2026-06-30
|
||||
|
||||
## 目标定位
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
- 平台超级管理员:管理所有租户、SaaS 套餐、年费/服务费、公共/地区题库披露。
|
||||
- 租户公司:拥有自己的品牌、域名、支付/登录/CRM 配置、成员角色、题库内容、销售/代理体系。
|
||||
- 学生端:刷题、错题、收藏、背单词、知识手册、分数线、视频解析、会员权益。
|
||||
- 跨端前端:后续 Taro 一套代码输出 H5 和小程序,统一调用 `apps/api`。
|
||||
- 跨端前端:Taro 一套代码优先输出 H5 学生端、租户后台和平台后台,后续继续扩展微信小程序,统一调用 `apps/api`。
|
||||
|
||||
## 当前覆盖情况
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
| 登录认证 | 可联调 | 短信 mock、阿里云/腾讯云短信 adapter、迁移期 session、Supabase Auth JWT、微信小程序登录、微信网页登录、QQ 登录、手机号绑定/换绑、OAuth 配置表 | 真实生产账号和回调域名联调 |
|
||||
| 支付 | 可联调 | 订单、支付记录、手动确认权限保护、权益发放、租户商户配置、微信支付 JSAPI、支付宝 WAP/H5、webhook 幂等、退款状态机、退款通知、补偿 worker、微信/支付宝官方账单下载 worker、资金对账导入比对、异常查询、差错工单和事件轨迹 | 异常订单运营台、真实生产账单格式验收、服务商/平台代收模式 |
|
||||
| AI 择校推荐 | 部分完成 | SVIP 门禁、学生输入 schema、地区/分数线上下文、`local_rules` 稳定 JSON 报告、报告台账/列表/详情、Taro 学生端基础页 | 真实 AI provider、prompt 版本管理后台、PDF 报告生成、人工复核和运营配置 |
|
||||
| Taro 跨端 | 未开始 | 旧 Web 新 API 适配开始 | `apps/taro`、共享 API client、H5/小程序统一构建 |
|
||||
| Taro 跨端 | 部分完成 | `apps/taro` 已有 Taro 4 React 工程、H5 学生端/租户后台/平台后台三套构建入口、统一 API client、Supabase Auth client、H5 `runtime-config.json` 运行时配置、学生端第一批学习页面、租户后台第一批运营页面、平台后台第一批管理页面 | 小程序真机兼容、支付/分享容器、公式真机验收、题图资源字段化、端到端测试和更完整 UI 打磨 |
|
||||
|
||||
## 接下来优先级
|
||||
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
- 明确 Taro 什么时候可以用 Supabase client,什么时候必须走 `apps/api`。
|
||||
6. `docs/refactor/taro-frontend-integration.md`
|
||||
- Taro 启动、租户解析、请求封装、页面/API 映射、跨端注意事项。
|
||||
7. `docs/refactor/multitenant-auth-security-contract.md`
|
||||
7. `docs/refactor/taro-h5-deployment.md`
|
||||
- H5 三域名部署、`runtime-config.json`、Nginx history fallback、缓存、CSP 和 CORS 边界。
|
||||
8. `docs/refactor/multitenant-auth-security-contract.md`
|
||||
- 多租户、鉴权、权限、资源签名和生产安全红线。
|
||||
8. `docs/refactor/content-import-contract.md`
|
||||
9. `docs/refactor/content-import-contract.md`
|
||||
- 后台内容导入、题目 JSON、单词、知识手册、分数线、视频的后端校验契约。
|
||||
|
||||
## 当前可进入的前端工作
|
||||
@@ -37,6 +39,7 @@
|
||||
- 可以接入迁移期短信登录和 `tk_` session,用于本地/内网联调。
|
||||
- H5 可以直接用 Supabase Auth access token 调 `apps/api`;后端已支持 JWT 验签和业务用户映射。
|
||||
- H5 可以优先验证 `@supabase/supabase-js` 管理 Auth session;微信小程序端先验证运行时兼容性,业务数据默认仍走 `apps/api`。
|
||||
- H5 生产部署优先用每个静态目录自己的 `runtime-config.json` 配置 `apiBaseUrl`、`supabaseUrl`、`supabasePublishableKey`、`tenantCode`;不要为了换域名重打包,也不要把任何 service role、数据库、支付、短信、对象存储密钥放进该文件。
|
||||
- 可以接入租户品牌、已发布主题、公开素材、功能开关和域名/小程序参数解析;学生端只读 `/api/tenant/resolve` 的 `branding.theme/publicAssets`,租户后台草稿走 `/api/tenant-admin/theme`。
|
||||
- 租户后台可以接入角色模板和成员 API:`/api/tenant-admin/role-templates`、`/api/tenant-admin/members`,用于运营、教师、销售、代理等自定义菜单/模块/字段可见性和成员模板绑定。
|
||||
- 租户后台可以接入勋章管理和手动发放:`GET/PUT /api/tenant-admin/badges`、`GET/POST /api/tenant-admin/badge-grants`;学生端用 `GET /api/profile/badges` 展示成就。
|
||||
|
||||
@@ -110,16 +110,19 @@ Taro 要同时支持 H5 和微信小程序。Supabase 官方 JavaScript client
|
||||
- 前端保存后端返回的 access token/session。
|
||||
4. 无论 H5 还是小程序,复杂业务数据默认调用 `apps/api`、Edge Function 或 RPC,不直接写 Supabase 表。
|
||||
|
||||
## 推荐前端环境变量
|
||||
## 推荐前端公开配置
|
||||
|
||||
只允许出现在前端构建中的变量:
|
||||
只允许出现在前端构建变量或 H5 `runtime-config.json` 中的公开配置:
|
||||
|
||||
```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
|
||||
TARO_APP_TENANT_CODE=<optional>
|
||||
```
|
||||
|
||||
H5 生产部署优先使用每个静态目录自己的 `runtime-config.json`,字段名可用 `apiBaseUrl`、`supabaseUrl`、`supabasePublishableKey`、`tenantCode`。这样学生端、租户后台、平台后台可以共用构建流程,各自按域名目录独立配置。完整规则见 `docs/refactor/taro-h5-deployment.md`。
|
||||
|
||||
禁止出现在前端:
|
||||
|
||||
```text
|
||||
|
||||
@@ -96,15 +96,17 @@ ALLOW_PLATFORM_ADMIN_KEY=false
|
||||
|
||||
这样旧式 `x-user-id` 和平台管理 key 会被拒绝,前端可以提前发现未按 session 接入的页面。
|
||||
|
||||
前端环境变量只允许包含:
|
||||
前端构建变量或 H5 `runtime-config.json` 只允许包含:
|
||||
|
||||
```text
|
||||
TARO_APP_API_BASE_URL
|
||||
TARO_APP_SUPABASE_URL
|
||||
TARO_APP_SUPABASE_PUBLISHABLE_KEY
|
||||
TARO_APP_PORTAL / portal
|
||||
TARO_APP_API_BASE_URL / apiBaseUrl
|
||||
TARO_APP_SUPABASE_URL / supabaseUrl
|
||||
TARO_APP_SUPABASE_PUBLISHABLE_KEY / supabasePublishableKey
|
||||
TARO_APP_TENANT_CODE / tenantCode
|
||||
```
|
||||
|
||||
禁止把 Supabase secret key、service role key、数据库连接串、对象存储密钥、支付私钥放进 Taro。
|
||||
H5 线上优先使用每个静态目录根部的 `runtime-config.json` 覆盖公开配置,避免 API/Auth 域名变化时重打包。完整部署、Nginx、CSP、缓存和 CORS 规则见 `docs/refactor/taro-h5-deployment.md`。禁止把 Supabase secret key、service role key、数据库连接串、对象存储密钥、支付私钥放进 Taro 构建变量或 `runtime-config.json`。
|
||||
|
||||
统一错误处理:
|
||||
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
# Taro H5 三入口部署说明
|
||||
|
||||
更新时间:2026-06-29
|
||||
更新时间:2026-06-30
|
||||
|
||||
当前 `apps/taro` 按一个 Taro 工程、三套 H5 产物组织:
|
||||
当前 `apps/taro` 采用一个 Taro 4 React 工程、三套 H5 产物的方式交付:
|
||||
|
||||
- 学生学习端:刷题、背单词、知识手册、分数线、资料、会员和个人中心。
|
||||
- 租户后台:品牌、域名、题库、导入、学生、订单、营销、销售和数据看板。
|
||||
- 学生学习端:刷题、背单词、知识手册、分数线、资料、会员、个人中心。
|
||||
- 租户后台:品牌、主题、域名、题库、导入、学生、订单、营销、销售、CRM、财务和数据看板。
|
||||
- 平台后台:租户、SaaS 套餐、订阅账单、公共题库授权和平台审计。
|
||||
|
||||
后续微信小程序仍复用同一套业务 services 和页面逻辑,但 H5 是当前优先上线形态。
|
||||
|
||||
## 构建命令
|
||||
|
||||
```bash
|
||||
@@ -26,27 +28,55 @@ apps/taro/dist/h5-platform-admin
|
||||
|
||||
推荐部署:
|
||||
|
||||
| 域名 | 目录 | 说明 |
|
||||
| 域名 | 静态目录 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `www.example.com` 或租户自有学生端域名 | `h5-student` | 面向学生和 C 端用户 |
|
||||
| `admin.example.com` | `h5-tenant-admin` | 面向租户公司运营、教师、销售、代理、管理员 |
|
||||
| `console.example.com` | `h5-platform-admin` | 面向平台超级管理员 |
|
||||
|
||||
三个入口可以放在同一台服务器的三个静态目录,也可以放到 CDN/对象存储静态网站。API 推荐独立域名,例如 `api.example.com`。
|
||||
三个入口可以放在同一台服务器的三个静态目录,也可以分别放到不同服务器或 CDN/对象存储静态网站。API 推荐独立域名,例如 `api.example.com`。
|
||||
|
||||
## 环境变量
|
||||
## 运行时配置
|
||||
|
||||
构建时只允许注入:
|
||||
H5 产物支持运行时覆盖公开配置。每个静态目录根部放一个 `runtime-config.json`:
|
||||
|
||||
```text
|
||||
TARO_APP_PORTAL=student | tenant-admin | platform-admin
|
||||
TARO_APP_API_BASE_URL=https://api.example.com
|
||||
TARO_APP_SUPABASE_URL=https://<supabase-auth-host>
|
||||
TARO_APP_SUPABASE_PUBLISHABLE_KEY=<publishable-key>
|
||||
TARO_APP_TENANT_CODE=<可选,小程序或预览环境使用>
|
||||
/www/tiku/h5-student/runtime-config.json
|
||||
/www/tiku/h5-tenant-admin/runtime-config.json
|
||||
/www/tiku/h5-platform-admin/runtime-config.json
|
||||
```
|
||||
|
||||
禁止进入前端构建:
|
||||
示例文件:
|
||||
|
||||
```text
|
||||
apps/taro/deploy/h5-student.runtime-config.example.json
|
||||
apps/taro/deploy/h5-tenant-admin.runtime-config.example.json
|
||||
apps/taro/deploy/h5-platform-admin.runtime-config.example.json
|
||||
```
|
||||
|
||||
生产示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"portal": "student",
|
||||
"apiBaseUrl": "https://api.example.com",
|
||||
"supabaseUrl": "https://auth.example.com",
|
||||
"supabasePublishableKey": "replace-with-supabase-publishable-key",
|
||||
"tenantCode": ""
|
||||
}
|
||||
```
|
||||
|
||||
允许字段:
|
||||
|
||||
```text
|
||||
portal student | tenant-admin | platform-admin
|
||||
apiBaseUrl apps/api 公开 HTTPS 地址
|
||||
supabaseUrl Supabase Auth/API 公开 HTTPS 地址
|
||||
supabasePublishableKey Supabase publishable/anon key
|
||||
tenantCode 小程序、预览环境或指定租户部署可用
|
||||
```
|
||||
|
||||
这些字段是前端公开配置,不是密钥。`apps/taro/src/env.ts` 会拒绝 `runtime-config.json` 中出现服务端密钥类字段,例如:
|
||||
|
||||
```text
|
||||
SUPABASE_SERVICE_ROLE_KEY
|
||||
@@ -60,34 +90,32 @@ AUTH_SESSION_SECRET
|
||||
PLATFORM_ADMIN_API_KEY
|
||||
```
|
||||
|
||||
`apps/taro/src/env.ts` 会在启动时检查这些危险变量,防止误把服务端密钥打包到前端。
|
||||
构建时仍可以设置同名 `TARO_APP_*` 变量作为默认值,但生产更推荐用 `runtime-config.json`。这样 API 域名、Auth 域名、租户预览码变化时不需要重新构建 H5。
|
||||
|
||||
## Nginx 建议
|
||||
## Nginx 示例
|
||||
|
||||
H5 使用 history 路由时,静态服务器需要把未知路径回退到 `index.html`。
|
||||
H5 使用 browser history 路由时,静态服务器需要把未知路径回退到 `index.html`。同时对 `runtime-config.json` 禁用缓存,对 hash 后的 JS/CSS 长缓存。
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name www.example.com;
|
||||
root /www/tiku/h5-student;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header X-Content-Type-Options nosniff always;
|
||||
add_header Referrer-Policy strict-origin-when-cross-origin always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https: blob:; font-src 'self' data:; connect-src 'self' https://api.example.com https://auth.example.com; media-src 'self' https: blob:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'" always;
|
||||
|
||||
location = /runtime-config.json {
|
||||
add_header Cache-Control "no-store" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
server_name admin.example.com;
|
||||
root /www/tiku/h5-tenant-admin;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
location ~* \.(?:js|css|woff2?|png|jpg|jpeg|gif|svg)$ {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
server_name console.example.com;
|
||||
root /www/tiku/h5-platform-admin;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
@@ -95,35 +123,78 @@ server {
|
||||
}
|
||||
```
|
||||
|
||||
API CORS 必须只允许实际域名,不允许生产环境 `CORS=*`。生产前运行:
|
||||
租户后台和平台后台复用同样规则,替换 `server_name`、`root` 和 CSP 中的 `connect-src` 域名即可。若学生端需要打开 OSS/COS/CDN 签名资源,`img-src/media-src` 可加入对应 HTTPS 域名;不要加入通配符 `*`。
|
||||
|
||||
```bash
|
||||
npm run readiness:production
|
||||
npm run readiness:production:db
|
||||
## CORS 和 Cookie
|
||||
|
||||
API 的生产 `CORS_ORIGIN` 必须只包含实际前端域名:
|
||||
|
||||
```text
|
||||
CORS_ORIGIN=https://www.example.com,https://admin.example.com,https://console.example.com
|
||||
```
|
||||
|
||||
禁止生产环境使用:
|
||||
|
||||
```text
|
||||
CORS_ORIGIN=*
|
||||
```
|
||||
|
||||
当前前端以 `Authorization: Bearer <supabase_access_token 或 tk_session>` 调用 API,`x-tenant-id` 只作为租户上下文,不作为身份来源。生产建议:
|
||||
|
||||
```text
|
||||
ALLOW_LEGACY_AUTH_HEADERS=false
|
||||
ALLOW_PLATFORM_ADMIN_KEY=false
|
||||
```
|
||||
|
||||
## 前端请求边界
|
||||
|
||||
- 所有页面统一通过 `apps/taro/src/services/api.ts` 调用后端。
|
||||
- H5 可以用 Supabase client 管理 Auth session,但业务数据默认走 `apps/api`。
|
||||
- `x-tenant-id` 只是租户上下文,不是身份来源。
|
||||
- 登录后禁止传 `x-user-id` 或 body/query `userId` 表示当前用户。
|
||||
- H5 可以用 Supabase client 管理 Auth session/JWT,但业务数据默认走 `apps/api`。
|
||||
- 订单、支付、权益、内容导入、后台配置、CRM、对象存储签名、视频播放签名必须走后端命令层。
|
||||
- 登录后禁止传 `x-user-id` 或 body/query `userId` 表示当前用户。
|
||||
- 私有 PDF、图片、视频不能由前端拼接 URL,必须使用 `content_assets` 和后端短签名。
|
||||
|
||||
## 发布步骤
|
||||
|
||||
1. 在新服务器或 CI 环境构建三套 H5:
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
npm run build:taro:h5:student
|
||||
npm run build:taro:h5:tenant
|
||||
npm run build:taro:h5:platform
|
||||
```
|
||||
|
||||
2. 拷贝静态产物到对应 Web 根目录。
|
||||
|
||||
3. 根据示例文件创建每个目录的 `runtime-config.json`。
|
||||
|
||||
4. 配置 Nginx history fallback、缓存策略、安全响应头和 HTTPS。
|
||||
|
||||
5. 配置 API 的 `CORS_ORIGIN`、Supabase Auth 回调域名、微信/QQ/支付宝/微信支付回调域名。
|
||||
|
||||
6. 运行生产就绪检查:
|
||||
|
||||
```bash
|
||||
npm run readiness:production
|
||||
npm run readiness:production:db
|
||||
npm run check:taro
|
||||
```
|
||||
|
||||
7. 打开三个域名,确认启动页能解析租户,登录后接口请求使用 `Authorization` 和正确的 `x-tenant-id`。
|
||||
|
||||
## 安全审计边界
|
||||
|
||||
H5 线上只发布 `apps/taro/dist/**` 静态文件,不要把 `apps/taro/node_modules` 或源码目录部署到 Web 根目录。后端/API/worker 的生产依赖审计使用:
|
||||
H5 线上只发布 `apps/taro/dist/**` 静态文件和每个目录自己的 `runtime-config.json`,不要把 `apps/taro/node_modules`、源码目录、`.env`、部署脚本缓存放进 Web 根目录。
|
||||
|
||||
后端/API/worker 的生产依赖审计使用:
|
||||
|
||||
```bash
|
||||
npm run audit:runtime
|
||||
```
|
||||
|
||||
Taro 4.2.0 当前构建工具链仍会触发 `npm run audit:taro:toolchain` 的上游 high/critical 告警,主要来自构建期 CLI、webpack、swiper、lodash-es 等传递依赖。不要使用 `npm audit fix --force` 将 Taro 降级到 3.x;应等 Taro 官方升级后再处理,或者后续评估 Vite runner 替代方案。上线时以静态产物、前端密钥检查、CORS 域名白名单和 API runtime audit 作为阻断项。
|
||||
Taro 4.2.0 当前构建工具链仍可能触发 `npm run audit:taro:toolchain` 的上游 high/critical 告警,主要来自构建期 CLI、webpack、swiper、lodash-es 等传递依赖。不要使用 `npm audit fix --force` 将 Taro 降级到 3.x;应等 Taro 官方升级后再处理,或后续评估 Vite runner 替代方案。上线时以静态产物、前端密钥检查、CORS 域名白名单、CSP 和 API runtime audit 作为阻断项。
|
||||
|
||||
## 下一步页面顺序
|
||||
## 小程序后续兼容
|
||||
|
||||
1. 学生端:租户启动、登录、首页、题库入口、练习、错题、收藏。
|
||||
2. 学生端:背单词、知识手册、分数线、资料、会员、个人中心。
|
||||
3. 租户后台:数据看板、内容导航、题目录入/导入、学生管理、营销中心。
|
||||
4. 平台后台:租户、套餐、账单、公共题库授权。
|
||||
5. 小程序:验证 storage/fetch/Auth 兼容性,复用同一套 API client。
|
||||
当前 `runtime-config.json` 只用于 H5。微信小程序版本应通过编译变量、小程序启动参数或后台小程序配置传入 `tenantCode`,再调用 `GET /api/tenant/resolve?tenantCode=...`。小程序端如 `supabase-js` 兼容性不稳定,保留 `apps/api/auth/*` 登录适配层,H5 继续使用 Supabase client 管理 Auth。
|
||||
|
||||
Reference in New Issue
Block a user