chore: add launch readiness smoke and tuning evidence

This commit is contained in:
Codex
2026-07-01 00:34:49 +08:00
parent 88640f8262
commit 53c96067ec
11 changed files with 1025 additions and 17 deletions

View File

@@ -91,10 +91,11 @@
- 生产 `.env` 模板和 `npm run readiness:production` / `npm run readiness:production:db` 已补,后续上云必须作为验收 gate。
- Auth/JWKS 上云后必须临时设置 `AUTH_SMOKE_*` 环境变量并运行 `npm run smoke:auth:remote`,真实 access token 不得写入仓库、前端配置或日志。
- 本地/预生产必须同时跑 `npm run test:rls`,它验证运行时 JWT claim 下的租户隔离,和 `readiness:production:db` 的静态 policy 检查互补。
- 已补 `npm run launch:gate` 生产上线证据门禁和 `docs/refactor/production-launch-evidence.template.json` 模板;最终切换前必须把 readiness、远程 Auth、RLS、生产 dry-run、导入校验、`pb:import:sample` 业务抽样、真实数据 API 读路径压测、API/worker/Taro、运行时审计、`@codex-security`、备份/回滚/真实抽样/生产 provider 等证据填入本地 `production-launch-evidence.json` 并通过门禁。
- 已补 `npm run launch:gate` 生产上线证据门禁和 `docs/refactor/production-launch-evidence.template.json` 模板;最终切换前必须把 readiness、远程 Auth、RLS、生产 dry-run、导入校验、`pb:import:sample` 业务抽样、真实数据 API 读路径压测、API/worker/Taro、运行时审计、`@codex-security`、备份/回滚/真实抽样/生产 provider 等证据填入本地 `production-launch-evidence.json` 并通过门禁。当前 Codex 环境未暴露可调用的 `@codex-security` 扫描工具时,该项只能标为待补,不能伪造完成。
- 确认数据库迁移流程、备份恢复、日志、告警。
- 准备 API 容器部署和 Supabase 云端/自托管连接方案。
- 已补 `npm run perf:api:local``docs/refactor/performance-benchmark-runbook.md`可在本地或云端对真实迁移数据做只读混合压测4 核 16G 正式容量报告需上云后按 6/30/50/100 阶梯并发复跑并归档到本地上线证据
- 已补 `npm run perf:api:local``npm run perf:summary``npm run perf:postgres:evidence``npm run smoke:launch-persona``docs/refactor/performance-benchmark-runbook.md`可在本地或云端对真实迁移数据做只读门禁、混合读写容量观察、PostgreSQL 调参证据和三类角色旅程烟测。2026-07-01 本地真实迁移库只读 30 worker/120s 为 108336 请求、0 错误、897.04 req/s、P95 68.32ms、P99 84.50ms;混合读写 50 worker/60s/10% 写入为 52979 请求、0 错误、870.42 req/s、P95 104.92ms、P99 136.22ms
- 当前本地 PostgreSQL evidence 仍提示 `jit=on``statement_timeout=0``idle_in_transaction_session_timeout=0``lock_timeout=0`;上云后必须按 `docs/refactor/postgresql-4c16g-tuning.md` 调整参数并复跑 evidence。4 核 16G 正式容量报告需上云后按 6/30/50/100 阶梯并发复跑并归档到本地上线证据。
### P1 商用功能完善

View File

@@ -19,6 +19,22 @@ npm run perf:api:local
- 默认不创建练习 session不写业务数据。
- 输出 JSON 和 Markdown 报告到 `docs/refactor/performance-reports/`。该目录已被 `.gitignore` 忽略,不应提交。
PostgreSQL 调参与运行证据:
```bash
npm run perf:postgres:evidence
```
该脚本会把关键 `pg_settings`、连接等待、缓存命中、大表大小和可选 `pg_stat_statements` Top SQL 输出到 `docs/refactor/launch-artifacts/`。调参前后各跑一次,配合 API 压测报告判断是否真正改善。
角色旅程烟测:
```bash
npm run smoke:launch-persona
```
该脚本从普通学生、租户管理员、平台管理员三个视角调用真实 API覆盖 SVIP 后刷题、收藏、错题复习入口、租户 dashboard/主题/学生/销售转化、平台租户/套餐/审计入口和越权拒绝。它会写入少量 `launch_persona_smoke` 测试练习与收藏记录,只建议在本地、预生产或灰度租户运行。
## 前置条件
本地真实迁移库压测:
@@ -120,6 +136,8 @@ npm run perf:api:local
| spike-100 | 100 | 2min | 否 | 短峰值和缓存命中观察 |
| spike-100-write | 100 | 2min | 是 | 短峰值刷题闭环,找 P95/P99 拐点 |
本地 Docker Desktop 可以先用同一矩阵做跑分,但只能证明代码、索引和本机 Docker 环境的趋势。正式容量承诺必须以目标云服务器、生产 PostgreSQL 参数、生产 API/worker 连接池、对象存储/CDN 和真实网络重新跑。
PowerShell 示例:
```powershell
@@ -203,6 +221,14 @@ npm run perf:summary -- --input docs/refactor/performance-reports/api-benchmark-
工具会从 `summary.errors``summary.errorRate``summary.latencyOk.p95Ms``summary.latencyOk.p99Ms``config.concurrency``config.durationSeconds``config.includeWrites` 生成 `launchGateCheck.summary`,并按上线门禁阈值返回退出码。通过后,把 `launchGateCheck.summary` 转写到 `production-launch-evidence.json``artifact` 保留对应日志或报告路径。
写入混合场景默认不会通过只读门禁。如果只是做容量观察,可以显式允许写入并使用写入场景阈值:
```powershell
npm run perf:summary -- --input docs/refactor/performance-reports/api-benchmark-20260630-xxxxxx.json --json --allow-writes --min-duration-seconds=60 --min-concurrency=50 --max-p95-ms=500 --max-p99-ms=1200
```
使用 `--allow-writes` 时,摘要工具输出 `capacityObservation`,不输出 `launchGateCheck`;不要把写入场景误填进生产上线门禁的 `performance.api-real-data-read`
更高的 50/100 并发、写入混合场景和容量结论仍应作为人工容量报告归档;门禁只负责挡住明显不达标的基础读路径。
证据中只记录报告路径、并发矩阵、P95/P99、错误率和结论不保存真实 token、支付密钥、用户隐私或完整响应。

View File

@@ -1,6 +1,6 @@
# 真实迁移数据 API 压测摘要
更新时间2026-06-30
更新时间2026-07-01
这份文件只记录脱敏后的聚合指标,便于 README、上线门禁和后续 AI 开发继续引用。原始 JSON/Markdown 报告位于已忽略的 `docs/refactor/performance-reports/`,不要提交到 Git。
@@ -8,8 +8,9 @@
- 环境:本地 Docker Desktop + 本地 Supabase/PostgreSQL + 本地 API 进程。
- 数据PocketBase 真实导出数据导入新 PostgreSQL 后压测。
- 数据规模:约 74,102 道题、1,597 个题目合集、3,102 个练习蓝图、3,500 个单词、2,676 条知识手册、3,670 个用户。
- 写入流量:开启真实刷题闭环,包含创建 session、拉取 session detail、提交若干答案、交卷和读取报告。
- 数据规模:当前真实迁移库约 74,117 道题、1,601 个题目合集、3,106 个练习蓝图、3,505 个单词、2,678 条知识手册、3,690 个用户、113,810 条答题记录、38,207 条错题和 458 条权益
- 写入流量:混合场景开启真实刷题闭环,包含创建 session、拉取 session detail、提交若干答案、交卷和读取报告。
- 商城说明:本地库的订单数据会受 seed、烟测和导入演练影响当前容量结论聚焦题库读写链路不用于推断 GMV、支付或订单峰值。
- 排行榜:未纳入默认压测,当前产品默认关闭排行榜。
- 说明:压测 worker 是无停顿请求流,不等同于真实在线学生数。真实在线容量需要前端埋点后按单个学生平均 RPS 折算。
@@ -34,11 +35,24 @@
| 100 | 60s | 8% | 59,123 | 0.00% | 969.92 req/s | 179.70 ms | 235.19 ms |
| 150 | 60s | 6% | 53,167 | 0.00% | 870.06 req/s | 298.23 ms | 402.89 ms |
### 2026-07-01 上线门禁与读写复核
这轮在同一套本地 Docker/Supabase 真实迁移库上执行,补充了只读上线门禁和 50 worker 混合读写复核。
| 并发 worker | 时长 | 刷题写入比例 | 请求数 | 错误率 | 吞吐 | P95 | P99 | 结论 |
| ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: | --- |
| 30 | 120s | 0% | 108,336 | 0.00% | 897.04 req/s | 68.32 ms | 84.50 ms | 通过只读上线门禁 |
| 50 | 60s | 10% | 52,979 | 0.00% | 870.42 req/s | 104.92 ms | 136.22 ms | 通过混合读写观察线 |
同轮 `npm run smoke:launch-persona` 已通过,覆盖普通学生 SVIP 后刷题、收藏、错题复习入口,租户管理员 dashboard/主题/学生/销售转化入口,平台管理员租户/套餐/审计入口,以及学生越权后台和跨租户访问拒绝。
同轮 `npm run perf:postgres:evidence` 运行成功,但本地默认 PostgreSQL 仍有生产前必须调优的 warning`jit=on``statement_timeout=0``idle_in_transaction_session_timeout=0``lock_timeout=0`。上云后要按 `docs/refactor/postgresql-4c16g-tuning.md` 调整并重启需要重启的参数,再复跑证据采集和压测。
## 初步结论
- 本地 Docker 环境下100 个无停顿 worker 内 P95 仍低于 300ms可以作为当前代码和索引状态的本地舒适区参考。
- 150 个无停顿 worker 仍然 0 错误,但 P95 在不同轮次中接近或超过 300ms已经能看到本地压力拐点。
- 如果未来前端真实埋点显示每名在线学生平均 0.05 到 0.2 req/s则 700 req/s 理论吞吐约对应 3,500 到 14,000 名活跃在线学生请求量;这只是吞吐换算,不是生产 SLA。
- 按最新 897 req/s 只读吞吐粗略折算,如果未来前端真实埋点显示每名在线学生平均 0.05 到 0.2 req/s理论请求吞吐约对应 4,485 到 17,940 名活跃在线学生;按更保守的 700 req/s 估算约为 3,500 到 14,000 名这只是吞吐换算,不是生产 SLA。
- 正式容量承诺必须在目标 4 核 16G 云服务器、生产 PostgreSQL 参数、对象存储/CDN、真实前端请求节奏和生产网络下复跑。
## 后续复测

View File

@@ -46,6 +46,25 @@
| `statement_timeout` | `30s` | `30s` | API 请求不应长期占用数据库;导入脚本用会话级覆盖 |
| `lock_timeout` | `5s` | `5s` | 防止普通请求长时间等锁 |
## 证据采集脚本
仓库已补上线前证据采集脚本:
```bash
npm run perf:postgres:evidence
```
脚本会输出 JSON/Markdown 到已忽略的 `docs/refactor/launch-artifacts/`,包含:
- `pg_settings` 中关键调参项、来源和 `pending_restart`
- `pg_stat_activity` 连接状态、锁等待和 I/O 等待聚合。
- `pg_stat_database` 事务、回滚和缓存命中率。
- `pg_stat_bgwriter` checkpoint 计数和耗时。
- public schema 大表估算行数、总大小和索引大小。
- 如已启用 `pg_stat_statements`,输出按总执行耗时排序的 Top SQL。
上云后建议顺序是:先采集一次默认值,应用本文件 shared-host 参数并重启需要重启的项,再采集一次,然后跑 API 阶梯压测。调参证据和压测报告一起进入本地 `production-launch-evidence.json`,不要提交真实证据文件。
## 应用连接池边界
4 核机器的关键不是把 `max_connections` 拉大,而是控制同时活跃 SQL 的数量。
@@ -173,6 +192,23 @@ limit 20;
- 没有 OOM、没有频繁连接耗尽、没有长时间 idle in transaction。
- 慢 SQL 日志能对应到具体接口、worker 或迁移脚本。
## pg_stat_statements
上线压测和灰度期间建议启用 `pg_stat_statements`。如果自托管 Supabase/PostgreSQL 允许修改 `shared_preload_libraries`,推荐:
```sql
alter system set shared_preload_libraries = 'pg_stat_statements';
```
该参数需要重启 PostgreSQL。重启后执行
```sql
create extension if not exists pg_stat_statements;
select pg_stat_statements_reset();
```
每轮压测后看总耗时、平均耗时和调用量最高的 SQL再决定是否新增索引、改 SQL、加预聚合或调整 API 缓存。不要把慢 SQL 明细直接提交到 Git因为其中可能包含业务表名、常量和内部路径。
## 压测闭环
调参后必须跑 API 压测,不要只凭参数表判断容量。当前仓库提供本地压测脚本:

View File

@@ -0,0 +1,117 @@
# Web 版上线前验收清单
更新时间2026-06-30
这份清单用于先上线 H5 Web 题库。Taro 仍然是前端工程,后端以 Supabase Auth/JWT、PostgreSQL/RLS、`apps/api`、worker 为主。前端视觉和交互可以参考 `F:\project\参考\旧题库小程序前端文件` 和旧 Web 版,但不能继承旧 PocketBase 直连、旧鉴权或旧字段模型。
## 前端接入原则
- H5 登录态优先使用 Supabase Auth access token。
- 复杂业务统一调用 `apps/api`,不要让页面直接写 Supabase 表。
- `runtime-config.json` 只能放 `portal``apiBaseUrl``supabaseUrl``supabasePublishableKey``tenantCode`
- 前端禁止出现 service role key、secret key、数据库连接串、OSS/COS 密钥、支付私钥、短信密钥。
- 页面层禁止手写 `x-user-id``Authorization``x-tenant-id`,统一使用 `apps/taro/src/services/api.ts`
- 私有图片、PDF、视频只消费后端短签名和 `content_assets` 权限结果,不能拼对象存储 URL。
- 学生头像只做男女预设,不做上传、裁剪或第三方头像同步。
- 排行榜默认不请求、不展示;只有租户购买/开启活动且完成专项压测后再接独立页面。
## 学生端验收旅程
用普通学生账号在 H5 走一遍:
1. 进入域名后能解析租户品牌、主题、公开配置。
2. 登录后 `GET /api/profile/me` 返回当前用户,不能靠页面传 userId。
3. 查看题库入口、地区、分类树、合集和练习蓝图。
4. 开通或确认 SVIP 权益后创建顺序/随机/模考 session。
5. 拉取 session detail刷新页面后仍能按后端 session 续练。
6. 提交答案、交卷、查看报告、逐题复盘。
7. 收藏题目,在个人中心或复习页进入收藏练习。
8. 产生错题后查看错题本、复习计划和错题复习 session。
9. 背单词:今日计划、单元学习、收藏练习、发音、进度上报。
10. 知识手册:章节、搜索、公式/图片/RichContent 安全渲染。
11. 分数线:地区、院校、专业、年份和动态字段筛选。
12. 资料下载:预览/下载前必须看到短签名、水印 traceId 或权限提示。
13. 视频解析:未授权提示、授权后短签名播放、水印上下文、次数扣减。
14. 订单:套餐、优惠券、下单、支付参数、订单详情、状态轮询、售后入口。
15. 个人中心:权益、学习统计、勋章、积分任务、兑换、站内通知。
自动烟测命令:
```bash
npm run smoke:launch-persona
```
该命令会写入少量测试练习和收藏记录,生产只在灰度/演练租户执行。
## 租户后台验收旅程
用租户管理员账号在 H5 走一遍:
1. 工作台模块按权限显示,学生账号访问后台必须 403。
2. 数据看板能按 7/30/90 天、地区读取收益、注册、学习、内容、活跃、反馈、激活码。
3. 学生运营列表、状态、批量导入、分班、备注、跟进任务、督导规则、CRM 推送。
4. 题库内容:入口、分类、题目集合、蓝图、题目/单词/手册/分数线/视频导入预览、异步 job、复检。
5. 营销中心:激活码、优惠券规则、核销报表、积分任务、兑换、勋章、用户通知。
6. CRM/分佣CRM 配置、队列、失败池、日志脱敏、重试/忽略、结算、凭证复核、销售转化报表。
7. 财务运营:退款、官方账单下载任务、对账异常、差错工单、人工调整凭证。
8. 设置:品牌、主题模板/草稿/发布、域名、支付账户、登录 provider、角色模板、成员绑定。
9. 跨租户访问必须拒绝,字段权限如手机号脱敏要按角色生效。
## 平台后台验收旅程
用平台管理员账号在 H5 走一遍:
1. 工作台、租户列表、租户详情、状态变更、账务资料维护。
2. SaaS 套餐、订阅、订阅账单候选、批量开票、收款、逾期催缴。
3. 用量记录、用量超额候选、超额账单生成。
4. 公共题库授权、租户可见范围、采纳/同步/冲突运营摘要。
5. 平台员工、权限点、禁用/恢复、受限员工越权拒绝。
6. 审计日志、CSV/JSON 导出、审计告警、外部通知渠道。
7. 学生或租户管理员访问平台后台必须 403。
## 安全与配置门禁
上线前至少执行:
```bash
npm run test:readiness
npm run test:rls
npm run audit:runtime
npm run check:api
npm run check:worker
npm run check:taro
npm run smoke:launch-persona
```
`@codex-security` 插件在当前 Codex 环境暴露扫描工具,再补插件扫描结果。若工具不可用,不能把该项标记为已完成,只能在上线证据里标记为待补。
生产 API 推荐:
```text
ALLOW_LEGACY_AUTH_HEADERS=false
ALLOW_PLATFORM_ADMIN_KEY=false
CORS_ORIGIN=https://student.example.com,https://tenant-admin.example.com,https://platform-admin.example.com
```
生产 worker 推荐:
```text
WORKER_ASSET_SECURITY_SCANNER=metadata_rules,http
WORKER_ASSET_SECURITY_SCAN_FAIL_OPEN=false
STORAGE_DEFAULT_PROVIDER=aliyun_oss 或 tencent_cos 或 supabase_storage
STORAGE_REQUIRE_TENANT_PREFIX=true
```
## 性能与数据库
本地真实迁移库已能跑题库读写压测,但正式容量必须在目标 4 核 16G 云服务器复测。
推荐顺序:
1. `npm run perf:postgres:evidence` 采集默认 PostgreSQL 参数。
2.`docs/refactor/postgresql-4c16g-tuning.md` 应用 shared-host 起步值。
3. 重启 PostgreSQL 后再次 `npm run perf:postgres:evidence`
4.`npm run perf:api:local` 的 6/30/50/100 阶梯,只读和少量写入各一组。
5. 把摘要写入本地 `production-launch-evidence.json`,执行 `npm run launch:gate`
容量折算不要直接把压测 worker 当在线人数。真实学生有读题和思考时间,应结合 H5 埋点估算单人平均 RPS再按成功 RPS 折算在线容量。