# 项目工程规则 版本:3.0 更新时间:2026-04-02 本规则是当前项目的真实工程约束,不是泛化建议。 ## 1. 基本原则 - 结论必须可验证,不能靠口头"已完成"。 - 优先真实闭环,拒绝 fake success、临时掩盖和只过局部样例。 - 任何上线结论都必须区分: - 浏览器级真实验证 - OS 级自动化 - 外部交付治理证据 - 迭代速度优先,但速度不牺牲质量:快速验证、快速反馈、快速修正。 ## 2. 后端规则 ### 2.1 运行时安全 - 非测试代码禁止保留 `panic` 作为常规失败路径。 - 配置不合法时应在启动期失败,不要运行后再暴露风险。 - 外部依赖缺失时必须显式禁用能力或启动失败,不能返回假成功。 ### 2.2 错误处理 - 必须保留真实错误语义,不能吞错。 - 优先使用显式错误分类: - 例如 rate limit - validation - internal failure - 禁止长期依赖字符串子串判断错误类型。 ### 2.3 分层设计 - service 层依赖接口能力,不依赖具体 repository 类型断言。 - repository 负责持久化细节,service 负责业务编排和错误分级。 - 外部副作用必须 fail closed,并处理回滚。 ### 2.4 安全与配置 - 敏感值不得硬编码到配置模板。 - release 模式必须限制: - 占位密钥 - localhost OAuth 回调 - `*` CORS 放行 - 不安全 JWT 配置 ## 3. 前端规则 ### 3.1 浏览器行为 - 原生弹窗和 popup 不是"可以接受的小问题",而是验收失败信号。 - 必须阻断并记录: - `alert` - `confirm` - `prompt` - `open` ### 3.2 主链路要求 - 登录页、后台主导航、路由守卫、认证状态恢复必须进入真实浏览器回归。 - 认证能力展示必须跟随后端 `capabilities`,不能前端硬编码。 ### 3.3 smoke 边界 - `smoke` 只允许存在于测试或诊断层。 - 任何产品运行时逻辑都不得依赖 `smoke`。 ## 4. 验证规则 ### 4.1 后端最低门槛 ```powershell go test ./... -count=1 go vet ./... go build ./cmd/server ``` ### 4.2 前端最低门槛 ```powershell cd frontend/admin npm.cmd run lint npm.cmd run build ``` ### 4.3 真实浏览器最低门槛 以下改动必须执行: ```powershell cd frontend/admin npm.cmd run e2e:full:win ``` 适用改动: - 认证 - 会话 - OAuth - 登录页 - 路由守卫 - 主导航 - `window` 防线 - 用户主流程 ### 4.4 测试覆盖要求 - 新增代码必须有对应测试。 - 修复 bug 必须有回归测试。 - 安全敏感代码必须有边界条件测试。 - 每个函数/方法必须有对应的单元测试。 - 跨模块交互必须有集成测试。 - 用户主流程必须有真实浏览器 E2E 测试。 ### 4.5 防虚假测试规则 - 禁止使用 mock 响应替代真实 API 调用进行 E2E 验证。 - 禁止在测试中硬编码预期结果而不走真实业务链路。 - 禁止跳过认证、权限校验等安全环节直接断言页面状态。 - 禁止在测试中使用 `context.Background()` 绕过上下文治理。 - 禁止在测试中注入假数据后直接断言页面显示而不验证后端存储。 - 禁止用 `smoke` 脚本的结果替代主验收路径。 ### 4.6 E2E 测试架构要求 - E2E 测试必须: - 启动真实后端进程(隔离测试数据库) - 启动真实前端开发服务器 - 通过真实浏览器(CDP 协议)执行用户操作 - 验证真实 API 响应(非 mock) - 验证真实数据库状态变化 - 当前项目的真实 E2E 路径: - Playwright CDP E2E:`cd frontend/admin && npm.cmd run e2e:full:win` - 覆盖场景:管理员引导、注册、邮箱激活、登录、认证工作流、响应式布局、桌面/移动端导航 - E2E 测试架构组件: - Playwright CDP 协议连接真实浏览器 - 隔离测试数据库(临时 SQLite 文件) - 本地 SMTP 捕获服务(验证邮件发送) - 信号收集器(console errors、dialogs、popups、request failures、401 responses) - 多视口验证(desktop 1440x960、tablet 820x1180、mobile 390x844) - 未来增强方向: - 引入 `agent-browser`(bb browse)等浏览器自动化工具,补充 Playwright 未覆盖的交互场景 - 增加复杂业务流程的端到端验证(如设备信任、批量操作、系统设置等) ## 5. 方案对比机制 ### 5.1 何时需要方案对比 - 新增核心功能或架构变更时。 - 存在多种可行实现路径时。 - 性能优化涉及重大权衡时。 ### 5.2 对比维度 - 实现复杂度(人天/智能体时) - 性能影响 - 可维护性 - 与现有架构的兼容性 - 测试难度 ### 5.3 决策记录 - 选定的方案必须记录决策原因。 - 被否决的方案必须记录否决原因。 - 决策记录写入 PR 描述或 `docs/decisions/` 目录。 ## 6. 文档规则 - 真实状态变化后必须更新 `docs/status/REAL_PROJECT_STATUS.md`。 - 团队长期规则变化后必须更新本文件和 `docs/team/PRODUCTION_CHECKLIST.md`。 - 形成阶段性经验后必须沉淀到 `docs/team/PROJECT_EXPERIENCE_SUMMARY.md`。 - 新增架构决策时,写入 `docs/decisions/` 目录。 ## 7. Gitea 协作规则 ### 7.1 分支策略 - `main` 分支:始终可构建、可测试通过,是唯一的发布基线。 - `feature/<简短描述>`:功能分支,每个独立功能一个分支。 - `fix/<简短描述>`:修复分支,每个独立修复一个分支。 - 禁止直接推送到 `main`,所有变更必须通过 PR 合并。 ### 7.2 PR 规范 - 每个 PR 只包含一个逻辑变更。 - PR 描述必须包含: - 变更目的(1-2 句) - 验证命令及结果 - 影响范围(后端/前端/文档) - PR 合并前必须通过最低验证矩阵。 ### 7.3 提交规范 - 提交信息格式:`类型: 简短描述` - 类型:`feat`、`fix`、`test`、`docs`、`refactor`、`chore` - 每次提交应该是可独立验证的最小单元。 ## 8. 多智能体并行工作流 ### 8.1 任务拆分原则 - 每个任务必须是独立的、可并行执行的单元。 - 任务之间如果有依赖,必须明确标注依赖关系和执行顺序。 - 前后端分离的任务优先并行执行。 ### 8.2 并行执行模式 - **方案对比阶段**:多个智能体并行输出不同方案,由决策者选择最优解。 - **实现阶段**:无依赖的任务并行执行,有依赖的任务按拓扑序执行。 - **验证阶段**:后端测试、前端 lint/build、E2E 测试并行执行。 ### 8.3 智能体分工 - **规划智能体**:负责任务拆分、依赖分析、方案对比。 - **实现智能体**:负责编码,每个智能体负责一个独立任务。 - **验证智能体**:负责测试执行、结果验证、报告生成。 - **审查智能体**:负责代码审查、安全审查、性能审查。 ### 8.4 冲突解决 - 多个智能体修改同一文件时,必须在任务拆分阶段识别并协调。 - 如果发生合并冲突,优先保留功能完整的版本,手动合并差异。 ## 9. 快速迭代规则 ### 9.1 迭代节奏 - 小步快跑:每个迭代周期不超过 2 小时。 - 持续验证:每个迭代完成后立即执行验证矩阵。 - 快速回滚:如果验证失败,立即回滚到上一个可用状态。 ### 9.2 阻塞处理 - 遇到阻塞时,立即记录阻塞原因和影响范围。 - 优先寻找替代方案,而不是等待阻塞解除。 - 阻塞超过 30 分钟必须上报并寻求协助。 ### 9.3 知识沉淀 - 每次解决的问题必须记录解决方案。 - 每次踩过的坑必须记录避免方法。 - 每次验证通过的命令必须记录执行结果。 ## 10. 禁止项 - 禁止"只跑单个用例就宣布收口"。 - 禁止"因为环境受限就把诊断脚本包装成主验收路径"。 - 禁止"为了通过测试保留运行时 mock provider"。 - 禁止"服务层通过具体仓储断言完成业务"。 - 禁止"因为终端乱码就把乱码字面量继续扩散到业务逻辑"。 - 禁止"用 mock 响应替代真实 API 调用进行 E2E 验证"。 - 禁止"在测试中硬编码预期结果而不走真实业务链路"。 - 禁止"跳过认证、权限校验等安全环节直接断言页面状态"。 ## 11. 2026-04-10 多轮 Review 新增质量规则 ### 11.1 stub 转 live 的复核门槛 - 任何从 stub、mock、`not implemented` 切换为 live 的接口,都必须重新做权限边界审查,不能沿用“之前只是占位实现”的风险判断。 - 这类改动至少补齐:正向用例、负向权限用例、边界条件用例、失败回滚用例。 - 若 live 化后暴露新治理风险,结论应以新风险为准,禁止因为“功能终于通了”而降低审查标准。 ### 11.2 RBAC / 管理员治理规则 - `GetUserRoles`、`AssignRoles`、`CreateAdmin`、`DeleteAdmin` 这类能力必须有显式权限控制,不能默认任何已登录用户可读写他人角色数据。 - 管理员治理必须包含 `self-action` 与 `last-admin` 防护:禁止自删管理员、禁止删除最后一个管理员、禁止把系统带入无管理员状态。 - 角色赋权、管理员创建、管理员删除这类多步写操作必须具备事务性;若底层不支持事务,必须提供显式回滚并有对应测试。 - 禁止在已有可靠角色解析或引导链路之外,再引入硬编码角色 ID 作为生产逻辑捷径。 ### 11.3 干净通过的定义 - `go test ./... -count=1` 与 `cd frontend/admin && npm.cmd run e2e:full:win` 是当前项目的真实发布门槛;局部命令绿灯、单步 build 绿灯、`-short` 绿灯都不能替代。 - 文档支持的主入口命令本身必须可复现;脚本包装器、临时缓存路径、工作目录切换等任一层失败,都应按真实失败处理。 - 测试完成后若仍输出 `window.alert`、`window.confirm`、`window.prompt`、`window.open` 或对应的 jsdom `Not implemented` 噪声,不算干净通过,必须继续治理。 ### 11.4 文档同步要求 - review 结论改变后,必须同步更新状态文档、门槛文档、技术指引和经验文档,禁止让旧结论继续充当协作依据。 - 文档中的”已闭环””可上线””已收口”表述,必须对应实际执行过的命令结果和当前支持的主验收入口。 ### 11.5 Swagger 注解完整性要求 - **每个 handler 方法必须有完整的 swagger 注解**,包括 `@Summary`、`@Description`、`@Tags`、`@Param`、`@Success`、`@Router`。 - 验证方法:每个新增方法必须通过 `grep -E “^func \(h \*[A-Za-z]+.*\) [A-Z]” .go | wc -l` 与 `grep -c “@Summary” .go` 比对。 - 禁止:只给部分方法添加注解就声称”已完成 swagger 文档”。 ### 11.6 响应格式统一性要求 - **所有 API 必须使用统一响应格式**:`gin.H{“code”: 0, “message”: “success”, “data”: ...}` - **白名单例外**(RFC 标准要求直接返回): - OAuth Token 端点(`/oauth/token`) - OpenID Connect UserInfo 端点 - **禁止**:在声称”已统一响应格式”后,仍有 handler 直接返回自定义结构体。 - 验证方法:`grep -rn “c.JSON.*TokenResponse\|c.JSON.*IntrospectResponse” internal/api/handler/` ### 11.7 测试基础设施完整性要求 - 所有测试引用的类型必须在代码库中定义。 - 验证方法:`grep -r “type IntegrationRedisSuite” internal/repository/` 必须返回定义位置。 - 禁止:测试文件引用未定义的类型,即使该测试有 `//go:build integration` 标签。 ## 2026-04-18 优化修复前治理基线 本附录定义了后续任何优化或修复工作开始前必须遵守的治理基线。若旧章节与本附录冲突,以本附录为准。 ### 1. 当前门禁真相优先 - 任何“当前状态”“已绿”“阻塞中”“可继续”的表述,都必须绑定当前工作区的新鲜命令证据。 - 报告日期事实与当前工作区事实必须分开书写。 - 历史绿灯结果不能复用为当前门禁证据。 ### 2. 当前优化修复的最低门禁 在声称一批修复已完成前,必须执行并记录: ```powershell go build ./cmd/server go vet ./... go test ./... -count=1 cd frontend/admin npm.cmd run lint npm.cmd run build ``` - 若改动涉及认证、会话、路由守卫、导航、`window` 防线或用户主流程,还必须执行: ```powershell cd frontend/admin npm.cmd run e2e:full:win ``` - 超时不算通过。 - 包装脚本失败就是真实失败。 - 成功摘要后仍有浏览器原生弹窗噪声,不算干净通过。 ### 3. 安全敏感修复必须 fail closed - refresh token 轮换在吊销持久化失败时必须 fail closed。 - 与 MFA 相关的登录逻辑在 TOTP/设备信任策略完成执行前,不能签发最终 token。 - CORS 必须拒绝危险默认组合,例如通配来源配合 credentials 开启。 - 任何由用户可控 ID 定位资源的接口,都必须在路由层或 handler 边界做显式授权检查。 ### 4. 正确性修复必须遵守契约 - cursor pagination 只能支持与游标谓词一致的排序;不支持的排序必须显式拒绝。 - 多步写操作必须具备事务性,或具备显式回滚逻辑。 - 基于缓存的安全计数器或一次性验证码必须使用原子语义,不能继续使用 best-effort 的读改写序列。 ### 5. 文档同步是强制项 - 若新鲜验证改变了真实门禁状态,必须在同一批次更新 `docs/status/REAL_PROJECT_STATUS.md`。 - 若评审改变了长期工程约束,必须在同一批次更新本文和 `docs/team/TECHNICAL_GUIDE.md`。 - 若评审产出了可复用经验,必须在同一批次更新 `docs/team/PROJECT_EXPERIENCE_SUMMARY.md`。 ### 6. 强制修复顺序 除非有更窄的依赖关系强制改变顺序,否则按以下次序执行: 1. 刷新当前门禁真相并写入文档。 2. 先修发布阻塞级别的安全与授权缺陷。 3. 为每个确认接受的修复补回归测试。 4. 重新执行受影响的完整门禁。 5. 只有在以上完成后,才进入结构清理或一般优化。 ## 2026-04-23 E2E Recovery Governance Supplement Use this section as the current normative supplement when older sections are silent on late-stage browser regressions. - Cursor pagination must separate the request cursor from the response `next_cursor`. If a page updates request state directly from the response on initial load, add a regression test proving it does not auto-fetch follow-up pages. - Frontend service adapters must decode backend envelopes by exact field names and must match the shared HTTP client contract exactly. Any admin API shape change requires a service-level regression test and at least one consuming page regression. - Admin-surface E2E assertions must prefer route, heading, role, or labeled-control locators. Broad text matching is not sufficient when the same text can appear in menus, cards, tables, and toasts. - When `cd frontend/admin && npm.cmd run e2e:full:win` fails in the late suite, triage in this order: backend contract mismatch, page-state or pagination bug, selector assumption bug, then CDP or browser-runtime instability. - Browser-suite retry code must refresh mutable preconditions such as `admin_bootstrap_required` from live backend capabilities before re-running scenarios against the same backend state. - When the supported browser gate changes from red to green or from green to red, update `docs/status/REAL_PROJECT_STATUS.md`, `docs/team/QUALITY_STANDARD.md`, `docs/team/TECHNICAL_GUIDE.md`, and `docs/team/PROJECT_EXPERIENCE_SUMMARY.md` in the same batch. ## 2026-04-23 Password Reset And CDP Stability Supplement - Capability endpoints must reflect real mounted-route availability. If password reset, email code, SMS code, or similar auth routes are conditionally mounted, the matching capability flags must be derived from the same condition or explicitly synchronized at assembly time. - A new auth or session browser scenario only counts as accepted when the targeted scenario is green and the full supported browser gate `cd frontend/admin && npm.cmd run e2e:full:win` is green on the same branch state. - Playwright CDP recovery must attempt connection-level recovery when the persistent page disappears late in the suite. Declaring failure before trying to reconnect is not an acceptable steady-state gate design. ## 2026-04-23 Permissions CRUD And Full Matrix Governance Supplement Use this section as the current supplement when older sections do not cover permissions CRUD closure or runner-observation mismatches. - If a frontend adapter normalizes backend enums or status values, the regression set must cover three layers on the same change: raw backend payload acceptance, normalized frontend read shape, and outbound write serialization. - Shared auth clients must attach the current non-expired access token immediately. An unrelated refresh already in flight is not a valid reason to downgrade a request to missing auth. - When a supported browser scenario depends on real network proof and CDP request or response observers miss the call, use evidence derived from the real page fetch path before classifying the failure as product behavior. Runner instrumentation must not silently redefine a healthy product as broken. - Modal, drawer, or overlay transitions that still intercept input after close has started must be treated as first-class E2E timing constraints. Wait for interaction blocking to stop, not only for a broad visibility assertion. - Backend handlers that accept admin CRUD writes must remain compatible with the payload forms actually sent by the current browser client during rollout, including numeric enum values such as permission `type=0` and mixed numeric or string status updates when those paths are supported. - Supported build commands are part of the release gate. If Vite or another build tool requires an explicit project root or equivalent configuration for the documented command to pass, fix the project config rather than relying on an ad hoc wrapper or local shell state. ## 2026-04-24 Profile Security Contract Recovery Supplement - If a form includes UI-only fields such as `confirm_password`, outbound service code must strip or remap those fields before hitting the API. UI form names are not a valid substitute for the backend write contract. - Service regression tests for write paths must assert the exact payload sent into the shared HTTP client, not only the values collected from the component or form layer. - Browser-runner fetch or response waiters must be action-scoped. A waiter that can outlive a failed action and later crash with a page-closed error is not acceptable verification infrastructure.