# CMPP 平台代码质量复评报告 V3 - 报告日期:2026-08-28 - 复评时间:2026-08-28 15:36~16:08(Asia/Shanghai) - 复评基线:`3834d67a308acf89d0e6cb2e6009c89c93b2c139` - 主要业务整改提交:`ad27acad7e02b787185c972c710c73c867429c36` - 锁文件修正提交:`226527f1cef122e4dbd163da782485e8c0254dc5` - 对比基线:V2 基线 `3af145abe5eb8cae567bb18e29116b4940889258` - Git 状态:本地 `main` 比 `origin/main` 超前 3 个提交;当前提交尚未推送 - 工作区保护:保留既有 `docs/code-quality-reassessment-20260828-v2.md` 修改、未跟踪 `=` 和 `pnpm-lock.yaml` - 明确未执行:提交、推送、部署、服务重启、数据库业务写入、短信发送、压力测试、预生产或生产操作 ## 1. 执行摘要 本轮综合判定为:**代码质量有条件通过,持续治理尚未闭环;不建议仅凭本报告进入预生产发布。** 与 V2 相比,本轮取得了明确进步: - 客户端凭据、Webhook、日志导出、文件上传、用户维护等写接口补充 class DTO、严格运行时校验和负向测试。 - 浏览器客户端请求不再发送或回退租户 ID,服务端可信租户边界进一步收紧。 - 登录保护从账号维度扩展为账号、来源 IP、账号+IP 和验证码请求频率,并使用 Redis 原子计数和摘要键。 - 建立 Vitest/Testing Library/jsdom/MSW 前端测试基座,4 个测试文件、34 项测试通过。 - API 增至 51 个测试套件、563 项测试并全部通过。 - 根依赖审计保持 0;API 审计从 V2 的 7 项降至 5 项,剩余项均位于 Prisma CLI 开发/迁移链。 - npm 10.9.4、两份正式 `package-lock.json`、ESLint flat config 和 Prettier 配置已建立。 - 测试环境已部署 `226527f...`;本次独立读取到的远端前端资源与本地构建资源一致,外部 API health 最终连续 5 次返回 200。 但本次独立复测发现两项不能忽略的问题: 1. **增量 lint/format 门禁存在假绿。** 默认比较 `HEAD` 时,提交后的整改文件不会进入检查;显式设置基线后,Windows 包装器又无错误信息地退出 1。绕过包装器直接检查 37 个整改代码文件,发现 6 个 ESLint error、2 个 warning,以及 2 个文件未通过 Prettier。 2. **客户端删除接口仍缺严格 DTO。** `ClientDeletionGovernanceController` 使用 TypeScript type `DeleteTargetDto`,没有 `strictValidationPipe`,额外字段、格式和长度仍不会按本轮统一规则拒绝。 综合参考分:**86/100**,较 V2 的 82/100 提升 4 分。P0 为 0,但仍有 2 项 P1 和若干 P2/验收边界。 ## 2. 质量评级 | 维度 | V2 | V3 | 结论 | |---|---:|---:|---| | 业务正确性与并发设计 | B+ | B+ | API/Gateway 全量回归通过;未重跑真实 CMPP 全链。 | | 安全性 | B+ | A- | 客户端租户边界、DTO 和登录保护明显增强;删除接口仍有校验缺口。 | | 自动化测试 | B- | B+ | 前端 34 项、API 563 项通过;API “全源”指标仍未成为标准脚本默认口径。 | | 前端性能 | B+ | B+ | 路由分包保持,入口 107.28 KiB gzip,图表异步包 181.65 KiB gzip。 | | 可维护性 | C+ | C+ | 引入 ESLint/Prettier,但门禁未真实通过;两个 SendChain Service 未拆分。 | | 数据库工程 | B+ | B+ | Prisma schema 和 95 项迁移发布记录正常;本轮未独立执行真实数据查询计划。 | | 依赖与仓库卫生 | B- | B | 根审计 0,API 风险降至 Prisma CLI 5 项;正式包管理器已固定,旧未跟踪 pnpm 锁仍在。 | | 运行与发布就绪 | B- | B | 测试环境公开入口及资源匹配;内部服务/队列状态仅有发布记录,本次 SSH 未独立复核。 | ## 3. V2 遗留项复核 | V2 项目 | V3 状态 | 复评结论 | |---|---|---| | 客户端写接口严格校验不完整 | **大部分关闭,仍有缺口** | 凭据、Webhook、导出、文件、用户等已补齐;客户端删除接口遗漏。 | | 前端自动化测试为 0 | **已关闭** | 4 个文件、34 项通过;覆盖登录、请求错误、租户头、路由异常和用户列表关键状态。 | | API 依赖公告 2 moderate/5 high | **部分关闭** | 当前为 2 moderate/3 high,共 5 项;均聚合在 Prisma CLI 链并有风险矩阵。 | | 无真实 ESLint/Prettier | **实现未验收通过** | 配置与脚本已增加,但增量包装器有缺陷,整改代码本身仍有 lint/format 失败。 | | SendChain 超大服务 | **未处理,按方案延期** | 文件仍约 86,253 和 53,421 字节;需要独立行为锁定与重构任务。 | | 双锁文件口径 | **部分关闭** | `packageManager` 固定 npm 10.9.4,正式仅跟踪两份 npm lock;旧未跟踪 pnpm lock 仍受保护保留。 | | 测试环境与登录后验收 | **部分关闭** | 测试环境已部署并健康;登录后深层页面和真实 CMPP 全链仍未复验。 | ## 4. 本轮独立验证结果 ### 4.1 构建与自动化测试 | 检查项 | 结果 | |---|---| | 前端 TypeScript | 通过 | | Vite production build | 通过 | | Bundle budget | 通过;入口 107.28 KiB gzip,Chart 181.65 KiB gzip | | 前端 Vitest | 4/4 文件、34/34 项通过 | | 前端纳入覆盖范围的核心模块 | statements 88.34%、branches 84.71%、functions 84.00%、lines 88.02% | | API TypeScript build | 通过 | | Prisma validate | 通过;仓库 95 项 migration | | API Jest | 51/51 套、563/563 项通过 | | API 默认 coverage 脚本口径 | 70.44% / 53.77% / 71.76% / 73.61% | | API 显式全源口径 | 60.46% / 51.54% / 60.75% / 63.04% | | API 增量覆盖配置 | 86.92% / 77.03% / 95.91% / 90.07% | | Gateway `go test ./... -count=1` | 通过 | | Gateway `go vet ./...` | 通过 | | Gateway 队列契约 | 5/5 通过 | | 结构质量/依赖缓解/安全部署门禁 | 通过 | | `npm ci --dry-run --include=dev` | 根项目与 API 均通过 | 覆盖率顺序均为 statements / branches / functions / lines。 首次并发执行前端测试时,4 个 Vitest worker 因本机同时运行多个高负载任务而启动超时,未执行测试;资源释放后以单 worker 串行重跑全部通过。首次从仓库根目录直接启动 API Jest 时误扫描受保护的 `outputs/` 历史快照;改为在 `api/` 目录按项目配置运行后全部通过。两次错误执行均未计为产品失败。 ### 4.2 覆盖率口径校正 `api/jest.config.cjs` 仍未配置 `collectCoverageFrom`,因此标准 `test:coverage` 的 70.44% 只统计测试实际加载的源码,不能称为严格“全源覆盖率”。本报告显式加入 `src/**/*.ts` 后的全源结果为 60.46% / 51.54% / 60.75% / 63.04%,较 V2 的 59.84% / 51.29% / 60.15% / 62.60% 小幅提升,并继续满足 59% / 50% / 60% / 62% 门槛。 增量配置确实对指定新增模块建立了 80% / 70% / 80% / 80% 门槛,但运行时仍执行全部 51 套测试;覆盖率只收集列出的 7 个文件。该机制有效,但文档应准确称为“指定整改模块覆盖率”,不应与全源口径混用。 ### 4.3 依赖审计 使用项目固定的 npm 10.9.4 直接审计正式锁文件: - 根项目:0 项公告。 - API:5 项公告,2 moderate、3 high。 - 5 项均为 `prisma -> @prisma/config/@prisma/dev -> deepmerge-ts/valibot` 聚合路径,不进入 NestJS HTTP 请求运行时。 - 自动修复建议是 Prisma 7.9.0 降级到 6.12.0,属于破坏性主版本变更,本轮不执行 `audit fix --force` 的决定合理。 - `api/package-lock.json` 已实际解析 UUID 11.1.1、find-my-way 9.7.0;Swagger、js-yaml、fast-uri、brace-expansion 的既有公告已关闭。 判定:供应链风险已从“未治理”转为“有记录的开发工具链风险接受”,但仍需监控 Prisma 上游修复。 ### 4.4 测试环境只读探测 - `curl --noproxy '*'` 绕过系统代理后,第一组 `/api/health` 3 次均为 HTTP 200。 - 同组客户端登录页、运营登录页和验证码接口均返回 200;运营登录页有一次总耗时约 9 秒。 - 随后一次 health 请求发生 10 秒连接超时;立即复测 5 次均返回 200,总耗时约 17~19 ms。 - 远端登录 HTML 引用 `index-BvZGIM6l.js` 和 `index-DyAqoJbu.css`,与本地 V3 构建产物一致。 - SSH 当前仍认证失败,无法独立读取 `.deployed-commit`、systemd、Redis Stream、migration 和服务器日志。 - 发布记录显示测试环境部署标记为 `226527f...`,95 项迁移一致、11 项服务 active、三条 Stream `pending=0/lag=0`、发布窗口 error 日志为 0;这些内部状态本次未独立复核。 判定:外部入口总体健康,单次超时暂记为网络瞬态,不设 P0;预生产前仍需用可用只读凭据复核内部状态。 边界说明:外部 smoke 曾请求一次验证码 GET 接口,该接口会在 Redis 写入一个 5 分钟 TTL 的一次性验证码记录;未提交登录、未创建用户或业务数据,未触发短信、余额、应用、通道或 MinIO 业务写入。 ## 5. 当前问题清单 ### CQ-QG-001 / P1:增量 lint/format 门禁假绿且整改代码未通过 **证据** - `tools/quality/run-changed-code-quality.mjs:7-14` 默认基线为 `HEAD`,正常提交后执行 `npm run lint` 时不会检查已提交整改代码。 - 本次默认运行输出 `No changed code files require lint/format`,不能证明 `ad27aca` 中的代码通过。 - 设置 `QUALITY_BASE_REF=3af145a...` 后,Windows 包装器无错误信息退出 1;脚本没有输出 `spawnSync` 的 error。 - 绕过包装器直接对 37 个整改文件执行 ESLint,发现 6 个 error、2 个 warning: - `api/src/auth/auth.controller.ts`:2 个未使用变量。 - `api/src/open-api/open-api.service.ts`:1 个未使用 import。 - `src/api/client/client.api.ts`:2 个未使用 import。 - `src/apps/client/ClientUsersPage.test.tsx`:1 个未使用变量。 - `src/apps/LoginPage.tsx`:Fast Refresh 导出警告、`useEffect` 缺少 `refreshCaptcha` 依赖警告。 - Prettier 检查发现 `api/src/auth/auth.service.spec.ts`、`api/src/open-api/open-api.service.spec.ts` 未格式化。 **影响** 整改记录中的“ESLint/Prettier 门禁通过”不是当前可重复证据。CI 如果没有显式传入基线会漏检提交;Windows 本地即使传入基线也会无诊断失败。 **关闭要求** 1. 门禁显式接收并验证 base/head,CI 使用 merge-base;本地提供全量或最近提交模式。 2. Windows 调用方式可执行,并在 spawn 失败时输出 `result.error`。 3. 修复 6 个 error、2 个 warning 和 2 个格式文件后,直接 ESLint/Prettier 与包装脚本均通过。 4. 为“无变更”“有错误”“Windows 启动失败”和“CI 基线”增加脚本测试。 ### CQ-API-001 / P1:客户端删除接口仍未纳入严格运行时校验 `api/src/deletion-governance/deletion-governance.controller.ts:34-38` 的客户端删除接口使用 `DeleteTargetDto`,但没有 `@UsePipes(strictValidationPipe)`;`api/src/deletion-governance/deletion-governance.service.ts:10-18` 的 DTO 仍为 TypeScript type,没有 class-validator 规则。请求中的额外字段、超长 reason、错误布尔类型、非法时间和幂等键格式不会按统一客户端策略拒绝。 关闭要求:建立 client deletion class DTO、严格管道和负向测试,并把结构门禁扩展为检查所有 `@Controller('client...')` 的 body 写接口,而不是仅靠人工清单。 ### CQ-COV-001 / P2:API 标准覆盖率脚本仍不是全源口径 标准 `test:coverage` 未配置 `collectCoverageFrom`,容易把 70.44% 误写为全源覆盖率;严格全源只有 60.46%。应在正式配置中固化全源 include/exclude,并保留增量覆盖作为第二道门禁。 ### CQ-MAINT-001 / P2:SendChain 超大服务仍未拆分 `send-inbound-entry.service.ts` 约 84.2 KiB,`send-gateway-submit.service.ts` 约 52.2 KiB。本轮明确延期是合理的风险控制,但不能记为质量治理完成。后续需先补行为锁定和性能基线,再分职责重构。 ### CQ-REPO-001 / P2:本地提交尚未推送且旧 pnpm 锁仍存在 本地比 `origin/main` 超前 3 个提交,远端凭据拒绝已在进度文档记录;测试环境部署了代码提交 `226527f...`,但远端 Git 仍停留在 V2 基线。灾备、协作和可追溯性因此不完整。另有未跟踪旧 `pnpm-lock.yaml`,虽未纳入正式流程,仍可能误导人工命令。 ### CQ-ACC-001 / P2:登录后浏览器和真实全链仍未复验 测试环境只验证了公开页面、验证码和 health;没有输入密码或代解验证码,没有验证登录后 loading/empty/error/refresh、权限和关键写操作,也没有重跑 PostgreSQL/Redis/MinIO/Gateway/CMPP 模拟器全链。自动化测试不能替代这些最终验收证据。 ## 6. 发布建议 当前建议:**允许继续整改和测试环境验证,暂停预生产发布。** 最小充分关闭顺序: 1. 修复增量 lint/format 包装器并清零当前 lint/format 失败。 2. 补齐客户端删除 DTO、严格校验和负向测试。 3. 把 API 严格全源覆盖率固化为标准门禁,修正文档口径。 4. 使用可用只读凭据复核测试环境部署标记、11 项服务、95 项迁移、Redis Stream 和 error 日志。 5. 在真实登录态下完成客户端/运营端关键页面和请求状态验收。 6. 取得授权后解决远端 Git 凭据并推送;推送不是本次复评授权范围。 7. SendChain 拆分继续作为独立高风险任务,不与上述门禁修复混合。 ## 7. 最终判定 - 原始安全 P0:**0 项未关闭**。 - 当前 P0:**0 项**。 - 当前 P1:**2 项**——质量门禁假绿、客户端删除校验遗漏。 - 当前 P2/验收边界:API 覆盖率口径、SendChain 重构、Git/锁文件治理、登录后与真实全链验收。 - 自动化:前端 34 项、API 563 项、Gateway 全包测试均通过。 - 构建与包体:通过。 - 依赖:根项目 0;API 5 项 Prisma CLI 风险已记录接受。 - 测试环境公开入口:通过,存在一次短暂超时后连续 5 次快速恢复。 - 代码质量:**86/100,有条件通过**。 - 持续治理闭环:**未通过**。 - 预生产发布建议:**暂停**。 本报告只对应固定提交和本次可重复证据,不把整改记录、单元测试或公开 health 冒充真实后端全链与登录后功能验收。