2026-04-02 11:22:17 +08:00
|
|
|
|
# 项目经验总结
|
|
|
|
|
|
|
|
|
|
|
|
更新时间:2026-03-25
|
|
|
|
|
|
|
|
|
|
|
|
这份总结只记录本项目已经真实发生过、并且已经影响工程决策的经验。
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 真正的收口来自证据,不来自感觉
|
|
|
|
|
|
|
|
|
|
|
|
- 只做代码修改,不做完整验证,不能称为收口。
|
|
|
|
|
|
- 这次项目推进中,真正有价值的闭环来自:
|
|
|
|
|
|
- `go test ./... -count=1`
|
|
|
|
|
|
- `go vet ./...`
|
|
|
|
|
|
- `go build ./cmd/server`
|
|
|
|
|
|
- `cd frontend/admin && npm.cmd run lint`
|
|
|
|
|
|
- `cd frontend/admin && npm.cmd run build`
|
|
|
|
|
|
- `cd frontend/admin && npm.cmd run e2e:full:win`
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 浏览器级真实 E2E 与 OS 级自动化不是一回事
|
|
|
|
|
|
|
|
|
|
|
|
- 当前项目已经形成稳定的浏览器级真实 E2E 路径。
|
|
|
|
|
|
- 但这不覆盖系统文件选择器、原生权限弹窗、桌面窗口层行为。
|
|
|
|
|
|
- 因此对外必须区分:
|
|
|
|
|
|
- 浏览器级真实验证已闭环
|
|
|
|
|
|
- 完整 OS 级自动化未闭环
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 字符串猜错误类型非常脆弱
|
|
|
|
|
|
|
|
|
|
|
|
- 邮箱验证码限流曾因为错误文本编码漂移,从 `429` 退化成 `500`。
|
|
|
|
|
|
- 短信发送也存在同类风险,甚至一度把限流错误错误映射成 `400`。
|
|
|
|
|
|
- 结论:
|
|
|
|
|
|
- 错误分级必须优先使用显式错误类型
|
|
|
|
|
|
- 旧字符串判断只能短期兼容,不能长期依赖
|
|
|
|
|
|
|
|
|
|
|
|
## 4. fake success 比直接失败更危险
|
|
|
|
|
|
|
|
|
|
|
|
- 邮件、短信、OAuth、上传这类链路,如果依赖缺失仍然返回成功,会让前端、测试和运营都得到错误信号。
|
|
|
|
|
|
- 这类问题不会减少故障,只会推迟暴露时间并放大排查成本。
|
|
|
|
|
|
- 结论:
|
|
|
|
|
|
- 运行时必须 fail closed
|
|
|
|
|
|
- 缺配置时要么禁用能力,要么启动失败
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 分层设计不是形式问题,而是稳定性问题
|
|
|
|
|
|
|
|
|
|
|
|
- TOTP 服务曾依赖具体仓储实现断言,导致 service 对替换实现和测试 mock 都很脆弱。
|
|
|
|
|
|
- 后续把依赖收回到接口能力后,分层更稳,测试也更自然。
|
|
|
|
|
|
- 结论:
|
|
|
|
|
|
- service 依赖接口,不依赖具体 repo 类型
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 非测试 `panic` 会放大生产风险
|
|
|
|
|
|
|
|
|
|
|
|
- 兼容入口中的 `panic` 即使当前主路径不用,也会在后续复用、测试或错误调用时变成进程级风险。
|
|
|
|
|
|
- 结论:
|
|
|
|
|
|
- 非测试代码中的 `panic` 必须持续清零
|
|
|
|
|
|
|
|
|
|
|
|
## 7. `smoke` 可以保留,但必须明确降级
|
|
|
|
|
|
|
|
|
|
|
|
- 诊断脚本有价值,但不能被包装成“主验收已通过”的替代品。
|
|
|
|
|
|
- 结论:
|
|
|
|
|
|
- `smoke` 只能做补充诊断
|
|
|
|
|
|
- 主验收必须走真实主链路
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 前端弹窗问题必须被当成缺陷,而不是小瑕疵
|
|
|
|
|
|
|
|
|
|
|
|
- 浏览器原生弹窗会直接打断真实后台主流程和自动化执行。
|
|
|
|
|
|
- 这次项目里,给 `window.alert/confirm/prompt/open` 增加阻断和日志后,验证稳定性明显提高。
|
|
|
|
|
|
- 结论:
|
|
|
|
|
|
- 原生弹窗和 popup 都应纳入失败信号
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 文档如果不跟着代码一起更新,很快就会反过来误导团队
|
|
|
|
|
|
|
|
|
|
|
|
- 真实状态、规则、发布门槛如果不及时更新,后续协作会不断重复已经踩过的坑。
|
|
|
|
|
|
- 结论:
|
|
|
|
|
|
- 状态、规则、经验、agent 都要跟代码一起维护
|
|
|
|
|
|
|
|
|
|
|
|
## 10. 接下来仍然属于真实缺口的部分
|
|
|
|
|
|
|
refactor: 整理项目根目录结构
整理内容:
- 删除 60+ 临时测试输出文件 (*.txt)
- 移动二进制文件到 bin/ 目录
- 移动 Shell 脚本到 scripts/ 目录
- scripts/dev/: check_gitea.sh, check_sub2api.sh, run_tests.sh
- scripts/deploy/: deploy_*.sh, simple_deploy.sh
- scripts/ops/: fix_nginx.sh, fix_ssl.sh, install_docker.sh
- scripts/test/: test_*.sh, test_*.bat
- 移动批处理文件到 scripts/
- 移动 Python 脚本到 tools/
- 清理临时日志文件
保留根目录必要文件:
- go.mod, go.sum, go.work
- Makefile, docker-compose.yml
- .env.example, .gitignore
- README.md, AGENTS.md, DEPLOY_GUIDE.md
验证: go build ./... && go test ./... 通过
2026-04-07 18:10:36 +08:00
|
|
|
|
以下不是"代码没写完",而是仍未形成完整外部交付证据:
|
2026-04-02 11:22:17 +08:00
|
|
|
|
|
|
|
|
|
|
- 真实第三方 OAuth live browser validation
|
|
|
|
|
|
- 外部 Secrets Manager / KMS 证据
|
|
|
|
|
|
- 多环境 CI/CD 密钥分发证据
|
|
|
|
|
|
- 跨历史版本 schema downgrade 回滚证据
|
|
|
|
|
|
- 完整 OS 级自动化证据
|
refactor: 整理项目根目录结构
整理内容:
- 删除 60+ 临时测试输出文件 (*.txt)
- 移动二进制文件到 bin/ 目录
- 移动 Shell 脚本到 scripts/ 目录
- scripts/dev/: check_gitea.sh, check_sub2api.sh, run_tests.sh
- scripts/deploy/: deploy_*.sh, simple_deploy.sh
- scripts/ops/: fix_nginx.sh, fix_ssl.sh, install_docker.sh
- scripts/test/: test_*.sh, test_*.bat
- 移动批处理文件到 scripts/
- 移动 Python 脚本到 tools/
- 清理临时日志文件
保留根目录必要文件:
- go.mod, go.sum, go.work
- Makefile, docker-compose.yml
- .env.example, .gitignore
- README.md, AGENTS.md, DEPLOY_GUIDE.md
验证: go build ./... && go test ./... 通过
2026-04-07 18:10:36 +08:00
|
|
|
|
|
|
|
|
|
|
## 11. 多智能体并行是提效的关键路径
|
|
|
|
|
|
|
|
|
|
|
|
- 2026-04-02 起,引入 Gitea 远程仓库作为协作基线。
|
|
|
|
|
|
- 后续迭代采用多智能体并行模式:
|
|
|
|
|
|
- 方案对比阶段:多个智能体并行输出不同方案,由决策者选择最优解。
|
|
|
|
|
|
- 实现阶段:无依赖的任务并行执行,有依赖的任务按拓扑序执行。
|
|
|
|
|
|
- 验证阶段:后端测试、前端 lint/build、E2E 测试并行执行。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- 任务拆分必须明确依赖关系,否则并行执行会互相阻塞。
|
|
|
|
|
|
- 多个智能体修改同一文件时,必须在任务拆分阶段识别并协调。
|
|
|
|
|
|
- 验证阶段并行执行可以显著缩短反馈周期。
|
|
|
|
|
|
|
|
|
|
|
|
## 12. 方案对比能避免走弯路
|
|
|
|
|
|
|
|
|
|
|
|
- 新增核心功能或架构变更时,必须先做方案对比。
|
|
|
|
|
|
- 对比维度:实现复杂度、性能影响、可维护性、与现有架构的兼容性、测试难度。
|
|
|
|
|
|
- 选定的方案必须记录决策原因,被否决的方案必须记录否决原因。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- 不经过方案对比直接实现,容易在后期发现更优方案,导致返工。
|
|
|
|
|
|
- 对比记录是团队知识沉淀的重要组成部分。
|
|
|
|
|
|
|
|
|
|
|
|
## 13. 快速迭代的核心是小步验证
|
|
|
|
|
|
|
|
|
|
|
|
- 每个迭代周期不超过 2 小时。
|
|
|
|
|
|
- 每个迭代完成后立即执行验证矩阵。
|
|
|
|
|
|
- 如果验证失败,立即回滚到上一个可用状态。
|
|
|
|
|
|
- 阻塞超过 30 分钟必须上报并寻求协助。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- 大步提交会增加回滚成本和排查难度。
|
|
|
|
|
|
- 快速验证能尽早发现设计断链和实现偏差。
|
|
|
|
|
|
- 持续验证比最终验证更可靠。
|
|
|
|
|
|
|
|
|
|
|
|
## 14. 测试全面性决定上线信心
|
|
|
|
|
|
|
|
|
|
|
|
- 新增代码必须有对应测试。
|
|
|
|
|
|
- 修复 bug 必须有回归测试。
|
|
|
|
|
|
- 安全敏感代码必须有边界条件测试。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- 没有测试的代码变更是定时炸弹。
|
|
|
|
|
|
- 回归测试能防止已修复的问题再次出现。
|
|
|
|
|
|
- 边界条件测试能发现最隐蔽的缺陷。
|
|
|
|
|
|
|
|
|
|
|
|
## 15. 虚假测试比没有测试更危险
|
|
|
|
|
|
|
|
|
|
|
|
- 虚假测试会给人"已通过"的错觉,推迟问题暴露时间并放大排查成本。
|
|
|
|
|
|
- 项目中发现过的虚假测试模式:
|
|
|
|
|
|
- 使用 mock 响应替代真实 API 调用进行 E2E 验证
|
|
|
|
|
|
- 在测试中硬编码预期结果而不走真实业务链路
|
|
|
|
|
|
- 跳过认证、权限校验等安全环节直接断言页面状态
|
|
|
|
|
|
- 在测试中使用 `context.Background()` 绕过上下文治理
|
|
|
|
|
|
- 结论:
|
|
|
|
|
|
- E2E 测试必须启动真实后端进程和前端服务器
|
|
|
|
|
|
- 必须通过真实浏览器(CDP 协议)执行用户操作
|
|
|
|
|
|
- 必须验证真实 API 响应和真实数据库状态变化
|
|
|
|
|
|
- 当前项目的真实 E2E 路径是 `cd frontend/admin && npm.cmd run e2e:full:win`
|
|
|
|
|
|
|
|
|
|
|
|
## 16. 浏览器自动化工具是 E2E 能力的延伸
|
|
|
|
|
|
|
|
|
|
|
|
- Playwright CDP E2E 已经覆盖管理员引导、注册、邮箱激活、登录、认证工作流、响应式布局、桌面/移动端导航。
|
|
|
|
|
|
- 但仍有一些复杂交互场景未被覆盖:
|
|
|
|
|
|
- 设备信任管理
|
|
|
|
|
|
- 批量操作
|
|
|
|
|
|
- 系统设置页
|
|
|
|
|
|
- 管理员管理页
|
|
|
|
|
|
- 登录日志导出
|
|
|
|
|
|
- 未来应引入 `agent-browser`(bb browse)等浏览器自动化工具:
|
|
|
|
|
|
- 补充 Playwright 未覆盖的交互场景
|
|
|
|
|
|
- 增加复杂业务流程的端到端验证
|
|
|
|
|
|
- 提供更灵活的用户操作模拟能力
|
2026-04-11 10:41:08 +08:00
|
|
|
|
|
|
|
|
|
|
## 17. 2026-04-10 多轮 Review 的新增经验
|
|
|
|
|
|
|
|
|
|
|
|
- 2026-04-08、2026-04-09、2026-04-10 的连续 review 证明:真正难的不是把 stub 改成 live,而是把 live 链路补到可治理、可回滚、可验证。
|
|
|
|
|
|
- `GetUserRoles`、`AssignRoles`、`CreateAdmin`、`DeleteAdmin` 从 stub 变成 live 后,问题从“功能没实现”升级成“权限边界、事务一致性、管理员治理是否成立”。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- “功能通了”不是结束,live 后第一轮就应该补越权读取、越权修改、自删管理员、最后管理员、失败回滚等负向验证。
|
|
|
|
|
|
- 高风险治理面不能靠默认假设,必须用显式规则和测试守住。
|
|
|
|
|
|
|
|
|
|
|
|
## 18. 主入口绿灯比局部绿灯更重要
|
|
|
|
|
|
|
|
|
|
|
|
- 连续 review 反复说明:`go vet ./...`、`go build ./cmd/server`、`go test ./... -short -count=1` 的绿灯,不能代替全量 `go test ./... -count=1` 与 `npm.cmd run e2e:full:win`。
|
|
|
|
|
|
- 2026-04-10 的 review 里,`LL_001` 仍让全量后端测试失败,`e2e:full:win` 仍卡在包装入口;这说明“单步可过”与“主入口可过”是两件不同的事。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- 发布判断必须跟着文档支持的主入口走。
|
|
|
|
|
|
- 任何脚本包装层失败都算真实失败,不应被下层局部绿灯掩盖。
|
|
|
|
|
|
|
|
|
|
|
|
## 19. 测试噪声也是质量问题
|
|
|
|
|
|
|
|
|
|
|
|
- 前端 `test:run` 与 `test:coverage` 即使最终返回成功,只要仍输出 `window.alert` 的 jsdom `Not implemented` 噪声,就说明代码库里还保留着会破坏真实交互的缺陷信号。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- “success summary 之后还有噪声”不算干净通过。
|
|
|
|
|
|
- 原生弹窗与 popup 应继续按缺陷治理,而不是按低优先级美观问题处理。
|
|
|
|
|
|
|
|
|
|
|
|
## 20. 文档如果慢于代码,会制造第二轮返工
|
|
|
|
|
|
|
|
|
|
|
|
- 多轮 review 的另一个稳定结论是:状态文档、质量规范、发布清单、技术指引如果不跟着真实结论更新,很快就会反向误导后续协作。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- review 一旦改变了真实结论,当轮就要同步文档。
|
|
|
|
|
|
- 文档不是收尾材料,而是下一轮决策的输入。
|
2026-04-11 23:38:43 +08:00
|
|
|
|
|
|
|
|
|
|
## 21. 部分完成等于未完成
|
|
|
|
|
|
|
|
|
|
|
|
- 项目中发现:声称"已添加 swagger 注解"但只添加了部分方法的注解。
|
|
|
|
|
|
- 项目中发现:声称"已统一响应格式"但 SSO handler 仍有 3 个端点未统一。
|
|
|
|
|
|
- 项目中发现:声称"已定义测试基础设施"但 IntegrationRedisSuite 类型从未定义。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- "80% 完成"在质量语境下等于"未完成"。
|
|
|
|
|
|
- 验证必须逐项,不能只看整体数字。
|
|
|
|
|
|
- 每次提交前必须运行完整性检查。
|
|
|
|
|
|
|
|
|
|
|
|
## 22. 完整性检查必须是自动化的
|
|
|
|
|
|
|
|
|
|
|
|
- 手动检查容易被跳过或遗漏。
|
|
|
|
|
|
- 经验教训:
|
|
|
|
|
|
- 必须有自动化检查脚本验证 swagger 注解完整性。
|
|
|
|
|
|
- 必须在 CI 中集成完整性检查。
|
|
|
|
|
|
- 必须在 PR 检查清单中明确列出完整性验证命令。
|
|
|
|
|
|
|
|
|
|
|
|
## 23. 声称 vs 实际的差距来源
|
|
|
|
|
|
|
|
|
|
|
|
虚假完成通常来自:
|
|
|
|
|
|
1. **部分完成就说完成**:swagger 注解 80% 完整就声称"已完成"
|
|
|
|
|
|
2. **格式不统一**:大部分统一但有例外就声称"已统一"
|
|
|
|
|
|
3. **类型未定义**:引用未定义的类型但测试没运行就声称"测试通过"
|
|
|
|
|
|
4. **覆盖率数字失真**:mock 测试占比高但计入覆盖率
|
|
|
|
|
|
|
|
|
|
|
|
防范措施:
|
|
|
|
|
|
- 完整性检查必须逐项
|
|
|
|
|
|
- 覆盖率必须验证真实测试运行
|
|
|
|
|
|
- 类型引用必须验证定义存在
|
2026-04-18 12:24:36 +08:00
|
|
|
|
## 2026-04-18 从复核到修复的经验
|
|
|
|
|
|
|
|
|
|
|
|
本附录记录了 2026-04-17 报告复核和 2026-04-18 文档对齐过程中提炼出的工程经验。
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 评审报告不是实时状态页
|
|
|
|
|
|
|
|
|
|
|
|
- 一份报告可以在技术上仍然有价值,但它的门禁摘要会很快过时。
|
|
|
|
|
|
- 团队必须把以下两类事实分开:
|
|
|
|
|
|
- 报告日期的发现
|
|
|
|
|
|
- 当前工作区的真实门禁状态
|
|
|
|
|
|
- 如果这两类事实混写,执行顺序和优先级判断会很快漂移。
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 新鲜命令证据优先于继承结论
|
|
|
|
|
|
|
|
|
|
|
|
- `go test ./... -count=1` 曾在评审材料里被视为红灯,但新鲜执行后在当前工作区已经转绿。
|
|
|
|
|
|
- 与此同时,前端 `lint` 已经重新变红。
|
|
|
|
|
|
- 经验:
|
|
|
|
|
|
在安排修复顺序前,必须先刷新真实门禁。
|
|
|
|
|
|
|
|
|
|
|
|
### 3. stub 转 live 会带来第二波风险
|
|
|
|
|
|
|
|
|
|
|
|
- `AssignRoles`、`CreateAdmin/DeleteAdmin`、`UploadAvatar` 已经越过了旧的“未实现”阶段。
|
|
|
|
|
|
- 一旦转为 live,主导风险就会从“功能缺失”切换为:
|
|
|
|
|
|
- 授权边界
|
|
|
|
|
|
- 事务性
|
|
|
|
|
|
- 公开暴露面
|
|
|
|
|
|
- 自操作 / 最后管理员治理
|
|
|
|
|
|
- 经验:
|
|
|
|
|
|
live 实现必须被当作新的安全与治理面重新复核,不能因为 stub 消失就直接标记为“闭环”。
|
|
|
|
|
|
|
|
|
|
|
|
### 4. 发布阻塞往往是策略链断裂,不是没写代码
|
|
|
|
|
|
|
|
|
|
|
|
- 密码登录绕过 TOTP/设备信任校验,比很多显眼的“功能缺失”更像真实发布阻塞项。
|
|
|
|
|
|
- refresh token 吊销 fail-open 也是发布阻塞项,即使代码路径本身已经存在。
|
|
|
|
|
|
- 经验:
|
|
|
|
|
|
在认证系统里,“已实现”不等于“完整”,只要安全策略链断了,就是关键缺陷。
|
|
|
|
|
|
|
|
|
|
|
|
### 5. 事实成立,不代表措辞可以粗糙
|
|
|
|
|
|
|
|
|
|
|
|
- LIKE 搜索问题是真实的,但把它笼统写成通用 SQL 注入,会夸大具体缺陷类型。
|
|
|
|
|
|
- 密码重置 replay 问题也是真实的,但必须精确指出脆弱路径。
|
|
|
|
|
|
- 经验:
|
|
|
|
|
|
严重级别可以保持不变,但措辞必须更精确;精确措辞能加快修复,也能减少无效争论。
|
|
|
|
|
|
|
|
|
|
|
|
### 6. 主入口绿灯比局部绿灯更重要
|
|
|
|
|
|
|
|
|
|
|
|
- 局部命令成功,不能替代项目正式支持的主命令成功。
|
|
|
|
|
|
- 包装层失败或顶层命令失败,就是真实项目失败,即使更深层子命令单独能过。
|
|
|
|
|
|
- 经验:
|
|
|
|
|
|
所有结论都必须对齐文档中声明的主验收入口。
|
|
|
|
|
|
|
|
|
|
|
|
### 7. 文档漂移会制造返工
|
|
|
|
|
|
|
|
|
|
|
|
- `REAL_PROJECT_STATUS`、评审报告和团队规范已经开始出现漂移。
|
|
|
|
|
|
- 这种漂移会把下一轮修复引向过时优先级。
|
|
|
|
|
|
- 经验:
|
|
|
|
|
|
文档更新不是交付后的清理工作,而是交付本身的一部分。
|