# AirShelf/core 性能验证闸(perf-probe) 给 **ralph-loop**(或人工)当 pass/fail 闸用的性能回归探针。全绿 → 退出码 0;任一硬闸不过 → 退出码 1 + `PERF-PROBE: FAIL`。 ## 一句话目的 逐页 + 逐接口验证「访问变快了 / 重复请求没了 / 但功能没改崩」。**改性能时反复跑它,直到全绿。** ## 怎么跑 先起前后端(后端 `:8010` 连真实 MySQL;前端 vite dev **必须带 /api 代理**): ```bash # 后端(backend/) DB_ENGINE=mysql .venv/bin/python manage.py runserver 127.0.0.1:8010 --noreload # 前端(frontend/)—— 记下它实际监听的端口(可能是 5173/5174) npm run dev # 探针(qa/function-audit/) node perf-probe.mjs --base http://127.0.0.1:5174 # 改成前端实际端口 node perf-probe.mjs --base http://127.0.0.1:5174 --only dashboard,projects node perf-probe.mjs --base http://127.0.0.1:5174 --headed # 看着跑 ``` 默认演示账号 `e2e-20260529-0806@airshelf.test` / `demo12345`;也可 `--token ` 免登录。 ## 闸怎么判(两层) ### 硬闸(确定性,挂 pass/fail) 1. **API 级:列表接口必须遵守 `page_size`** —— `?page_size=200` 要全部一页拉得到时,`next` 必须为 `null`、条数 = `count`。 *当前根因*:`/api/assets/` 无视 `page_size=200`,死按 20 条/页返回 → 前端 `allAssets` 被迫并行翻 N 页(资产越多页越多)。 2. **浏览器级:任意页面不得出现资产分页瀑布**(`/api/assets/?page=2…`)。这是上面那条的直接症状。 3. **功能守护**:每页必须真渲染(没掉回登录页)、所有接口 `< 400`、bootstrap 必须在 25s 内发起(否则=后端慢到没加载出来,判失败防假通过)。 > 为什么 API 检查 + 浏览器双保险:浏览器按时序数瀑布会被后端延迟抖动影响(慢时漏抓)。API 断言与时序无关、永不抖,是真正的硬闸;浏览器只作功能守护 + 佐证。 ### 软提示(打印不挂闸,留给架构决策) - **接口延迟**:本地连远程 MySQL 每次握手 ~1.6s,绝对 ms 天然抖,不宜当硬闸;但打印出来暴露**疑似 N+1 的慢接口**(基线里 `/api/projects/` ~2s、`/api/ops/notifications/` ~1.4s,大概率缺 `select_related/prefetch_related`)。 - **首屏接口数超预算**:每页 bootstrap 拉了 ~9 个全局接口(products/projects/assets/billing/trend/members/models/tasks/notifications),且**每个路由都重拉一遍**——连 `/account` 这种用不到的页也拉。这是架构性过量拉取,**怎么改属设计决策**(懒加载 / 按页取数 / 引入 react-query 缓存层),不由闸强判,见下。 ## 基线(2026-06-17,优化前) - ❌ `/api/assets/` page_size 未生效(count=194 → 返回 20、next 有)→ **根因**。 - ❌ dashboard / projects / account 等出现 9 页资产瀑布。 - ⚠ `/api/projects/` ~2s、`/api/ops/notifications/` ~1.4s(疑似 N+1)。 - ⚠ 每页首屏 9~18 个接口(bootstrap 每页重拉)。 - ✅ 全部页面功能正常、无接口报错。 ## 优化方向(供参考,不替代设计决策) 1. **修 `page_size` 根因(后端)**:让 `/api/assets/` 真正应用 `AssetPagination`(`max_page_size=200`)。这一条修好,前端瀑布自动消失。 2. **修 `allAssets` 兜底(前端 `src/api.ts`)**:别用 `results.length` 反推页数;按 `count` + 真实 `page_size` 算,或直接跟 `next`。 3. **慢接口补 ORM**:`/api/projects/`、`/api/ops/notifications/` 等加 `select_related/prefetch_related`、确认有分页。 4. **(设计决策)bootstrap 瘦身**:全局只加载真正全站要用的;各页数据按需懒加载 + 缓存,避免每路由重拉 9 个接口。**此项请人工拍板方案再做。** ## 给 ralph 的硬规矩 - 严禁删功能换性能;严禁为过闸放宽断言阈值或把检查注释掉。 - 每轮改完必须重跑 `node perf-probe.mjs --base <前端端口>`,全绿(`PERF-PROBE: PASS`)才算完成。 - 改后端任务/接口代码后注意:本地不起 worker,纯接口改动 runserver 即时生效。