# 整体开发流程

> **版本**: v2.1
> **最后更新**: 2026-05-16（新增"通用工程 pattern"段：Ratchet 棘轮 + 三层完工模型）
> **适用范围**: 全体研发（含 AI 助手协作）

---

## 核心约定

### 目标

- 定义从需求确认到交付上线的标准阶段、交付物与验证要求。
- 为 AI 优先开发环境提供统一的项目组织方式、执行边界与验证闭环。
- 让 AI 助手在同一套事实源下稳定执行，而不是依赖零散 prompt。

### AI-first 方法论

本项目的核心信条：**默认一切由 AI 完成，人工介入需要理由。**

- **AI 默认，人工例外** — 每项工作先问"AI 能不能做"，而不是"需不需要 AI 帮忙"。如果 AI 做不了，思考如何改进流程、文档或工具让它能做。
- **规格驱动实现** — 文档是唯一事实源，AI 依据规格生成代码。无文档不实现。
- **人类聚焦不可替代的事** — 定义业务目标、编写规格、做判断性决策、验收最终结果。
- **持续复盘人机分工** — 定期回顾：哪些工作是人做的？能否通过改进 skills、文档或工具转交给 AI？

### 核心原则

1. `docs/` 是事实源，负责保存稳定规则、契约与流程说明。
2. `AGENTS.md`、`CLAUDE.md` 等入口文件是项目级正式入口，负责高频规则、导航、工具说明与最小执行约束；稳定契约仍以 `docs/` 为准。
3. `.agents/skills/` 是共享 skills 唯一事实源；工具目录只做分发，不做人肉维护入口。
4. `scripts/`、`.githooks/`、CI 必须把关键规则自动化，不能只靠文档提醒。
5. 任何 AI 产出都必须可验证、可复现、可 review。
6. AI-first 开发体系本身应持续演进，允许在开发过程中主动发现并推动更优方案。

### 实际开发流程

有了需求后，开发全程通过调用 AI skills 完成：

```
1. 人：描述需求（1-3句话）
2. AI：@plan-feature 多角度需求澄清 → 产出需求分析摘要
3. 人：确认需求摘要 ★ 唯一决策点 ★
4. AI：@start-feature 创建分支和隔离环境，填写 TASK.md
5. AI：@docs-main 产出 PRD + API 草稿 + 数据模型草稿
6. AI：@database-main 设计/变更数据库 schema
7. AI：@backend-main 实现后端 API 和业务逻辑
8. AI：@frontend-main 实现前端页面和组件
9. AI：@test-main 跑完整测试（L0→L1→L2）
10. AI：@git-main 提交、推送、创建 PR
11. 人：review PR → 合并（轻量，测试全绿即可合并）
```

不是每个需求都走全部步骤——按实际需要跳过不涉及的步骤。

人在这个流程中做**两件事**：**确认需求摘要（步骤 3）、合并 PR（步骤 11）**。其余全程由 AI 自主执行。

### 开发流程全景图（四层环境）

整体分四层，AI 主场逐层收紧、人工把关逐层加重：**L1 本地（AI 全权）→ L2 Dev（AI 自动化主场）→ L3 UAT（人工业务验收）→ L4 Production（最严人工 + 灰度）**。每一层有明确的"做什么 / 准入 / 准出 / 谁负责"，前一层未达准出，后一层不应启动。

> **本图描述目标设计**。部分项当前 CI 尚未实施——L2 失败 Discord 通知/自动回滚、L3 部署后 L1c（已迁到 nightly-snapshot-check）、L4 灰度部署、L4 自动回滚。**CI 实施现状以 [docs/ops/02-ci-cd-architecture.md](../ops/02-ci-cd-architecture.md) 为准**——发现两份文档冲突时，相信 yml + 02。

```
┌──────────────────────────────────────────────────────────────────────────────────┐
│                       开发流程全景图（四层环境）                                     │
└──────────────────────────────────────────────────────────────────────────────────┘

╔══════════════════════════════════════════════════════════════════════════════════╗
║ L1  本地开发（feature/* 分支）                              负责人: AI 全权          ║
╠══════════════════════════════════════════════════════════════════════════════════╣
║ 准入: 需求澄清 + 人工确认 PRD 摘要 [skill: plan-feature → 人工 gate]                 ║
║                                                                                  ║
║ 做什么:                                                                           ║
║   ① 契约面判定 → 触碰则先补/对齐 docs/modules/{m}/  [skill: contract-check]         ║
║   ② 建分支 + worktree                              [skill: start-feature]         ║
║   ③ 文档先行（缺口先补）                            [skill: docs-main]              ║
║   ④ schema 变更                                    [skill: database-main]         ║
║   ⑤ API + 业务逻辑                                 [skill: backend-main]           ║
║   ⑥ 页面 + 组件                                    [skill: frontend-main]          ║
║   ⑦ 按改动范围匹配测试（"改哪测哪"）:                                                 ║
║       ├─ 改 frontend 入口/页面 → L0 页面清点（生成本次测试范围清单）                   ║
║       ├─ 改 schema/migrations → 测试库验证迁移      [skill: database-main]          ║
║       ├─ 改 backend → 受影响模块 L1 集成测试        [skill: test-backend]            ║
║       ├─ 改 frontend → 本地起 dev + Playwright    [skill: test-frontend]           ║
║       │                MCP 跑改动页面（双语+边界）                                   ║
║       ├─ 改契约面（API/字段/状态机）→ L0a/L0b 静态契约校验                           ║
║       ├─ 改 backend API 返回结构 → L0c 响应快照（启本地 dev + curl 比对）             ║
║       ├─ 改 seed.ts 或 schema → 本地 L1c 数据质量（验种子数据结构/JSONB/FK）          ║
║       └─ 纯文档/纯重构 → 跳过测试                                                   ║
║   ⑧ 代码精简                                       [skill: simplify / /simplify]   ║
║   ⑨ 提交前 Lint/Type check + build（只 build 改动侧：[skill: pre-merge-build-fix] ║
║       动了 backend 才 build backend，动了 frontend 才 build frontend）              ║
║   ⑩ 提交 + 推送 + 提 PR → develop                  [skill: git-main]               ║
║                                                                                  ║
║ 准出: 本地 build 绿 / 改动范围内的测试全绿 / 文档同步 / 迁移文件 ≤1 / PR 已创建         ║
║ 不做: 跨模块全量回归（L3 兜底）/ 全链路 E2E（L3 兜底）/ 性能压测                        ║
║ 失败成本: 零，重做                                                                  ║
╚════════════════════════════════════╤═════════════════════════════════════════════╝
                                     │  PR (feature → develop)
                                     ▼
╔══════════════════════════════════════════════════════════════════════════════════╗
║ L2  Test 环境（develop 分支，ffworkspace.test.faradayfuturecn.com）         负责人: AI 自动化（人不介入）    ║
╠══════════════════════════════════════════════════════════════════════════════════╣
║ 准入: PR 已开 + L1 准出全绿                                                        ║
║                                                                                  ║
║ 做什么:                                                                           ║
║   PR 阶段（quality-gates.yml CI 门禁，硬阻断）:                                      ║
║     ├─ verify-agent-assets（资产同步校验）                                          ║
║     ├─ build-check（backend nest build + frontend next build，自带 tsc 类型检查）    ║
║     ├─ migration-file-count（迁移文件数量 ≤ 1）                                      ║
║     ├─ contract-check（L0a/L0b 请求/响应字段对齐）                                   ║
║     ├─ backend-integration（L1 集成测试 + L0c 响应快照同 job 内跑）                   ║
║     └─ ai-review（required，硬阻断）                    [skill: code-review]          ║
║   merge 后:                                                                       ║
║     ├─ 自动部署 → ffworkspace.test.faradayfuturecn.com                    [skill: deploy-ops]            ║
║     ├─ 健康检查 + smoke 200（不跑 E2E，节省 CI 资源）[skill: infra-check]            ║
║     ├─ L1c 数据质量校验（test 环境累积数据 JSONB/FK） [skill: test-main]            ║
║     └─ 失败 → Discord 通知 + 自动回滚              [skill: troubleshoot]           ║
║                                                                                  ║
║ 定位: 永远可看的整体效果环境，PM/设计/其他开发随时点开看现状                            ║
║ 数据: 可脏，定期 reset，不进真实用户数据                                              ║
║ 不跑 E2E: AI 高频合并 develop（10+次/天），跑 E2E 会拖死 CI；E2E 全部留给 L3 兜底     ║
║ 准出: merge 成功 + test 部署成功 + 健康检查通过 → 才可开 PR develop→staging          ║
╚════════════════════════════════════╤═════════════════════════════════════════════╝
                                     │  PR (develop → staging)，攒批发布
                                     ▼
╔══════════════════════════════════════════════════════════════════════════════════╗
║ L3  UAT 环境（staging 分支，ffworkspace.test.faradayfuture.com）          负责人: AI 跑机械活 + 人工业务验收 ║
╠══════════════════════════════════════════════════════════════════════════════════╣
║ 准入: L2 准出全绿 + test 环境验证无回归                                               ║
║                                                                                  ║
║ 做什么（不重跑 L2 已过的 contract / build / 受影响模块 L1，那些已经绿了）:               ║
║   PR 阶段:                                                                        ║
║     ├─ AI Review 出审核报告（聚焦本批次合并风险） [skill: code-review]               ║
║     └─ 人工 final approve（必需）                                                  ║
║   merge 后:                                                                       ║
║     ├─ 自动部署 → ffworkspace.test.faradayfuture.com                    [skill: deploy-ops]             ║
║     ├─ 跑【全量】L1 集成（跨模块回归，不限受影响）  [skill: test-backend]              ║
║     ├─ 跑【全量】L2 E2E（所有关键流，不限改动页）  [skill: test-frontend]             ║
║     ├─ L1c 数据质量校验（UAT 验收库，部署后跑）   [skill: test-main]                 ║
║     └─ 用户/PM 执行 L3 人工验收（视觉/体验/业务流/边界/双语）                          ║
║                                                                                  ║
║ 定位: 用户视角的最后一道关，数据接近生产（脱敏快照）                                    ║
║ 准出: 全量回归绿 + L1c 绿 + 独立 CI 脱敏快照校验绿 + UAT 验收签字                     ║
║       → 才可开 PR staging→production                                              ║
╚════════════════════════════════════╤═════════════════════════════════════════════╝
                                     │  PR (staging → production) 或 hotfix→production
                                     ▼
╔══════════════════════════════════════════════════════════════════════════════════╗
║ L4  Production（production 分支）                负责人: 强制人工 approve + AI 监控  ║
╠══════════════════════════════════════════════════════════════════════════════════╣
║ 准入: L3 验收签字 + 独立 CI 脱敏快照校验绿 / hotfix 走加急通道也必须经过 L2 验证        ║
║                                                                                  ║
║ 做什么（L4 不跑业务回归/E2E，但跑生产独有的"环境层"检查）:                              ║
║   PR 阶段:                                                                        ║
║     ├─ AI Review 报告（聚焦发布风险/回滚预案）    [skill: code-review]               ║
║     ├─ Migration 部署前审查（耗时预估/锁表风险）  [skill: database-main]              ║
║     └─ 人工强制 approve（且 reviewer ≠ PR 作者）                                    ║
║   部署前:                                                                         ║
║     ├─ 环境变量必填项校验（DATABASE_URL/外部 API key 等）[skill: deploy-ops]          ║
║     ├─ 连通性检查（DB/Redis/MQ/第三方 API 可达） [skill: infra-check]               ║
║     └─ 数据库备份 + 回滚预案就位                 [skill: db-backup]                 ║
║   部署后（关键，不可省）:                                                            ║
║     ├─ Smoke test（健康检查/登录能进/首页200/关键API200）[skill: deploy-ops]         ║
║     ├─ 灰度阶段关键指标监控（错误率/p95/QPS/慢SQL）[skill: infra-check]              ║
║     ├─ 自动部署 + 灰度（如适用）                  [skill: deploy-ops]               ║
║     ├─ AI 持续监控（日志/告警/关键指标）          [skill: infra-check]               ║
║     ├─ L1c 数据质量持续监控（生产 read-only 定期跑） [skill: test-main]              ║
║     ├─ 数据库定期备份（独立于部署前的应急备份）   [skill: db-backup]                  ║
║     ├─ 异常告警推 Discord                        [skill: troubleshoot]             ║
║     └─ 出问题触发回滚到上一个 production tag（人工确认）                              ║
║                                                                                  ║
║ 关键认知: L4 跑的是"环境层"检查（env/连通性/smoke/灰度指标），不是"代码层"检查           ║
║          （回归/E2E/单元）；后者由 L3 兜底，前者只有生产能跑                            ║
║                                                                                  ║
║ 铁律: 绝不 SSH 改文件 / 绝不手工改库 / 绝不 force-push                                ║
║ 准出: 监控期 N 小时无回滚 / 关键指标在阈值内 → 本次发布关闭                             ║
╚══════════════════════════════════════════════════════════════════════════════════╝

跨层阻断规则（任一不满足，立刻停止，不前进到下一层）:
  • 文档缺失（契约面）→ 不实现
  • 本地 build 失败 → 不提交
  • L0a/L0b/L0c 契约校验 ❌ → 不合并
  • CI 任何硬阻断 ❌ → 不合并
  • L2 部署 / 健康检查失败 → 不开 PR 到 staging（E2E 在 L3 跑，不在 L2 阻断）
  • UAT 未签字 → 不开 PR 到 production
  • 人工未 approve（L3/L4） → 不合并
```

#### 分层检查的设计原则

四层检查的取舍源于业界三个共识——**测试金字塔 + 左移 + 抽样升级**：早层窄而快、晚层宽而深；能在前面抓到的不拖到后面；每层样本逐步接近真实环境。

**核心原则（按优先级）**

1. **每类检查只在"最早能抓到 + 最后兜底"两个点跑**，中间层不重复
2. **失败立即停**：L0 失败不跑 L1、L1 失败不部署、L2 失败不开 PR 到 staging——每层失败都不浪费下一层资源
3. **左移昂贵的检查**：能在 L1 抓出来的（类型错误、契约不一致、迁移文件超标），绝不拖到 L2 才发现
4. **L1/L2 同类检查不算重复**：L1 是"开发者自检，减少 CI 返工"（本地 30 秒 vs CI 5 分钟），L2 是"环境一致性兜底"（本地能跑 ≠ CI 能跑）——价值不重叠
5. **L3/L4 不重跑 L2 已过的检查**：代码没变，contract / build / 受影响 L1 已经绿过；L3 跑 L2 没跑的全量 + 真实数据 + 人工，L4 不跑测试只做最终把关 + 监控
6. **L4 不跑"代码层"测试，但必须跑"环境层"检查**：业务回归/E2E/单元测试 L3 已兜底，L4 跑这些 ROI 为零；但**生产独有**的失败场景（env 差异、第三方真实凭证、migration 在真实数据上的表现、CDN/资源限制、灰度阶段流量行为）只有 L4 才能验，必须跑 smoke test + 配置校验 + 灰度监控

#### 检查归属矩阵（避免跨层重复，提高性价比）

每类检查只在"最早能抓到"和"最后兜底"两个点跑，中间层不重复。原则：**早层窄而快、晚层宽而深**。

注：检查命名沿用项目三层测试体系（详见本文档"测试策略"章节）——L0 页面清点 / L0a/L0b 契约校验 / L0c 响应快照 / L1 集成（L1a API 结构 + L1b 业务规则）/ L1c 数据质量 / L2 E2E / L3 人工验收。**L0 页面清点严格说是"测试范围规划"而非测试本身**，列在矩阵中提示"什么时候做"，结果不是 pass/fail 而是范围清单。


| 检查类型                         | L1 本地              | L2 Dev CI/部署       | L3 UAT             | L4 生产              |
| ---------------------------- | ------------------ | ------------------ | ------------------ | ------------------ |
| **静态检查**                     |                    |                    |                    |                    |
| Lint / Type check            | IDE/CLI            | 门禁                 |                    |                    |
| build（前后端）                   | 改动侧                | 全量门禁               |                    |                    |
| 迁移文件数量 ≤ 1                   | 提交前                | 门禁                 |                    |                    |
| **代码层（依赖代码本身）**              |                    |                    |                    |                    |
| L0 页面清点（规划用，输出清单非 pass/fail） | 前端改动时              |                    |                    |                    |
| L0a/L0b 契约校验                 | 快反馈                | 门禁                 |                    |                    |
| L0c 响应快照                     | 改 API 时            | 门禁                 |                    |                    |
| L1 集成（L1a + L1b）             | 改哪测哪（受影响模块）        | 门禁（受影响模块）          | 全量跨模块回归（merge 后兜底） |                    |
| L1c 数据质量（JSONB/FK）           | 改 seed.ts/schema 时 | merge 后跑（test 累积数据） | 部署后跑（UAT 验收库）     | 持续监控（生产 read-only） |
| L2 E2E                       | 改动页（本地 MCP）        |                    | 全量 + 双语            |                    |
| L3 人工业务验收                    |                    |                    | 视觉/体验/业务流/边界/双语    |                    |
| AI Review                    |                    | 硬规则 block          | 批次审                | 发布风险               |
| 人工 approve                   |                    |                    | 业务验收               | 强制（≠ 作者）           |
| **环境层（依赖目标环境）**              |                    |                    |                    |                    |
| 环境变量校验 / 连通性检查               |                    |                    |                    | 部署前                |
| Migration 风险审查               |                    |                    |                    | 部署前                |
| Smoke test（健康检查/关键路径）        |                    |                    |                    | 部署后                |
| 灰度阶段指标监控                     |                    |                    |                    | 灰度期间               |
| 持续监控告警                       |                    |                    |                    | 持续                 |
| 数据库备份                        |                    |                    |                    | 定期                 |
| **未来扩展（暂时不做，遇到问题再加）**        |                    |                    |                    |                    |
| 性能 / 压测（k6/JMeter）           |                    |                    |                    | ⏳ p95 飙高时加         |
| 安全扫描 - `npm audit`           |                    | ⏳ 可立即加             |                    |                    |
| 安全扫描 - SAST/DAST             |                    | ⏳ 合规要求时加           |                    |                    |
| 视觉回归（Percy/Chromatic）        |                    |                    | ⏳ MCP 漏检时加         |                    |
| 可访问性（axe-core）               |                    |                    | ⏳ a11y 要求时加        |                    |


> 此矩阵的 WHY 见上文"分层检查的设计原则"——尤其原则 4（L1/L2 不算重复）和原则 5（L3/L4 不重跑）。

**矩阵外的独立检查：L1c 生产脱敏快照校验**

不绑定 L1-L4 任一环境，作为独立 CI 任务跑。临时拉起一个 DB 加载脱敏快照、跑 L1c 校验脚本、跑完销毁——不挤占 UAT 验收数据库。

- **触发时机**：Nightly 定时 + PR develop→staging（准入 L3 前）+ PR staging→production（准入 L4 前）
- **作用**：抓"生产真实数据特有的结构问题"（如老业务数据残留的 JSONB 空数组、断 FK），是 L4 上线前最后一道数据层兜底
- **失败处理**：发现脏数据 → 走数据修复流程，不阻断代码发布

### 测试数据生命周期图

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                        测试数据生命周期                                        │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  force-reset（一次性）                                                        │
│  ┌──────────────────────────────────────────────┐                           │
│  │  DROP DATABASE                                │                           │
│  │       ↓                                       │                           │
│  │  CREATE DATABASE                              │                           │
│  │       ↓                                       │                           │
│  │  prisma db push （创建所有表）                   │                           │
│  │       ↓                                       │                           │
│  │  seed.ts （写入种子数据）                         │                           │
│  │    ├─ 角色: Administrator, Employee, ...       │                           │
│  │    ├─ 权限: user:read, user:create, ...       │                           │
│  │    ├─ 岗位: CEO, CTO, CFO, ...               │                           │
│  │    └─ 工作流角色: APPLICANT, DIRECT_MANAGER, ...│                           │
│  └──────────────────────┬───────────────────────┘                           │
│                         │                                                    │
│                         ▼                                                    │
│  每个测试用例（循环 N 次）                                                       │
│  ┌──────────────────────────────────────────────┐                           │
│  │                                               │                           │
│  │  beforeEach:                                  │                           │
│  │  ┌────────────────────────────────────┐       │                           │
│  │  │ ① cleanupAllData()                 │       │                           │
│  │  │    精确 DELETE 测试数据               │       │                           │
│  │  │    ├─ 删: user_role_rel (全部)      │       │                           │
│  │  │    ├─ 删: users (非种子)            │       │                           │
│  │  │    ├─ 删: roles (非内置)            │       │                           │
│  │  │    ├─ 删: organizations (全部)      │       │                           │
│  │  │    ├─ 删: departments (全部)        │       │                           │
│  │  │    └─ 保留: 种子角色/权限/岗位         │       │                           │
│  │  │                                    │       │                           │
│  │  │ ② 创建临时 admin                    │       │                           │
│  │  │    username: t_{timestamp}_admin    │       │                           │
│  │  │    → 分配 Administrator 角色(种子)   │       │                           │
│  │  │    → 登录拿 token                   │       │                           │
│  │  │                                    │       │                           │
│  │  │ ③ 创建测试资源（按需）               │       │                           │
│  │  │    组织: t_{ts}_ORG                │       │                           │
│  │  │    部门: t_{ts}_ROOT               │       │                           │
│  │  │    用户: t_{ts}_user               │       │                           │
│  │  └────────────────────────────────────┘       │                           │
│  │                                               │                           │
│  │  测试用例执行:                                   │                           │
│  │  ┌────────────────────────────────────┐       │                           │
│  │  │  用 adminToken 调 API               │       │                           │
│  │  │  断言响应 + 验证数据库                 │       │                           │
│  │  └────────────────────────────────────┘       │                           │
│  │                                               │                           │
│  │  → 下一个测试用例（回到 beforeEach ①）        │                           │
│  └──────────────────────────────────────────────┘                           │
│                                                                             │
│  关键规则:                                                                    │
│  • 种子数据全程不删，只在 force-reset 时创建                                      │
│  • 测试数据必须带随机标识（t_{timestamp}_xxx）                                    │
│  • cleanup 用精确 DELETE，禁止 TRUNCATE                                        │
│  • raw SQL 禁止空 catch，必须 console.warn                                     │
│  • Prisma model 名 ≠ SQL 表名，写 SQL 前查实际表名                               │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## 项目组织

### 推荐目录分层


| 层级   | 位置                                                   | 职责                       |
| ---- | ---------------------------------------------------- | ------------------------ |
| 事实源  | `docs/`                                              | 架构、规范、模块契约、运维手册、验证方法     |
| 项目入口 | `AGENTS.md`、`CLAUDE.md`                              | AI 助手正式入口、必读规则、常用命令、技能入口 |
| 共享技能 | `.agents/skills/`                                    | 跨工具复用的执行流程、模板、脚本、参考资料    |
| 分发目录 | `.claude/skills/`                                    | Claude Code 消费的同步产物（Codex CLI 直接读 `.agents/skills/`）|
| 自动化  | `scripts/`、`.githooks/`、CI                           | 同步、校验、构建、测试、阻断违规操作       |
| 验证留痕 | `testing/reports/`                                   | 测试报告、集成验证记录、失败阻断说明       |


### 项目组织规则

1. 新规则先判断应归属 `docs/`、入口文件、skills 还是脚本，禁止一条规则多处定义。
2. 面向模块的业务契约统一进入 `docs/modules/{module}/`，遵循文档依赖顺序。
3. 面向组织级研发流程的规范统一进入 `docs/standards/`。
4. 面向工具的执行流程放入 `.agents/skills/`，必要时引用 `docs/` 中的权威文档。
5. 面向运行时执行的约束，优先落到 hooks 或 CI，而不是只写在文档里。

### AI 协作规则

1. 单次任务要有清晰边界、可交付结果和验证方式。
2. AI 助手开始实现前，必须先定位权威文档与相关 skill。
3. 需求变化先改文档，再改代码；紧急修复可先修复，但必须补记录。
4. AI 助手产出的代码、文档、测试与脚本都需要人工 review。
5. 失败经验需要回灌到 `docs/`、`.agents/skills/`、`scripts/` 或 hooks，形成闭环。
6. 在日常开发中，如发现文档、模板、skills、hooks、脚本或流程存在明显更优方案，应主动提出并推动优化。

### 如何使用事实源

- 业务需求与契约：看 `docs/modules/`
- 组织级规范：看 `docs/standards/`
- 运维与发布：看 `docs/ops/`
- 环境与基础设施：看 `docs/infrastructure/`

入口文件（`AGENTS.md`、`CLAUDE.md`）应当告诉 AI：

- 先读哪些文档
- 哪些目录能改、哪些不能改
- 哪些 skills 可用
- 哪些脚本和 hooks 会阻断违规操作
- 当前入口特有的高频规则和维护约束

---

## 完整流程（按阶段组织）


| 顺序  | 阶段          | 需要解决的问题                   | 产物/结果                                       |
| --- | ----------- | ------------------------- | ------------------------------------------- |
| 1   | 需求与文档闭环     | 目标、范围、约束、依赖文档是否已明确        | 模块文档闭环（结构遵循 `docs/documentation-system.md`） |
| 2   | 前端原型（按需）    | 是否需要通过界面与用户快速确认需求         | 可演示 Demo、关键交互、Mock 数据                       |
| 3   | 数据结构设计（如涉及） | 数据模型、约束、迁移路径是否成立          | `06-data-model.md` + Prisma 变更/迁移           |
| 4   | API 与后端实现   | 契约、服务逻辑、权限、错误映射是否完整       | 服务/控制器/接口实现 + 契约对齐 + 角色权限种子更新               |
| 5   | 前端实现        | 页面、组件、交互、状态与真实接口是否完成      | 页面/组件/交互实现                                  |
| 6   | 文案与本地化（如涉及） | 用户可见文案是否完成并符合规范           | 统一 i18n 键与翻译                                |
| 7   | 测试与验证       | 后端逻辑→前后端连通→用户体验是否分层验证     | 测试结果 + 验证步骤                                 |
| 8   | Git 与评审     | 是否已通过分支、PR、状态检查与人工 review | 可合并变更                                       |
| 9   | 回顾与规则沉淀     | 过程中发现的问题是否已沉淀为规则          | 更新的规范/skill/memory                          |


### 阶段输入与输出


| 阶段        | 最小输入           | 最小输出                                                                       |
| --------- | -------------- | -------------------------------------------------------------------------- |
| 需求与文档闭环   | 需求背景、目标用户、范围边界 | 已更新的模块文档或标准文档                                                              |
| 前端原型（按需）  | 待确认的页面、流程或交互问题 | 可演示原型、反馈记录、确认结果                                                            |
| 数据结构设计    | 已确认的业务规则与状态约束  | 数据模型、迁移方案、约束说明                                                             |
| API 与后端实现 | 已确认的交互和数据结构    | API、服务逻辑、错误映射、权限实现                                                         |
| 前端实现      | 已确认的契约与设计规范    | 接真实接口的页面与组件                                                                |
| 测试与验证     | 已完成实现          | 分层测试结果（L0a/L0b 契约校验 → L1 集成测试 → L1c 数据质量 → L2 MCP E2E → L3 人工验收）、测试报告（如适用） |
| Git 与评审   | 已通过本地验证的变更     | PR、状态检查、评审结论                                                               |


### 阶段文档要求


| 阶段        | 必要文档                        | 可选文档                                     | 最小必填项                                                           |
| --------- | --------------------------- | ---------------------------------------- | --------------------------------------------------------------- |
| 需求与文档闭环   | `01-prd.md`                 | `02-user-journey.md`                     | 目标、范围、核心规则、验收标准                                                 |
| 前端原型（按需）  | `05-ui-interaction-spec.md` | `02-user-journey.md`、原型反馈记录              | 页面/弹窗、关键交互、成功/失败反馈、待确认项                                         |
| 数据结构设计    | `06-data-model.md`          | `04-state-machine.md`                    | 实体、字段、关系、约束                                                     |
| API 与后端实现 | `07-api.md`                 | `08-error-codes.md`、`03-architecture.md` | 端点、请求/响应、权限、错误                                                  |
| 前端实现      | `05-ui-interaction-spec.md` | `02-user-journey.md`                     | 页面、元素、交互、状态                                                     |
| 测试与验证     | `09-test-scenarios.md`      | `10-e2e-test-spec.md`、测试报告、验收清单          | L0 契约校验通过 + L1 集成测试通过 + L1c 数据质量校验（如适用）+ L2 MCP 连通性验证 + L3 人工验收 |
| Git 与评审   | 变更说明、验证结果                   | 测试报告、评审记录                                | 改动摘要、影响范围、验证结论                                                  |


### 决策点（必须回答）

- 是否需要先与用户通过界面确认需求？（是 → 使用 `frontend-main` 的原型模式）
- 是否涉及数据库/Prisma 变更？（是 → 必用 `database-main`）
- 是否有用户可见文案或翻译变更？（是 → 选择相应前端/后端流程并补齐 i18n）
- 是否涉及 API 变更？（是 → 先跑 L0 契约校验，再跑 L1）
- 是否需要 E2E？（关键流程/高风险端点 → 推荐执行 L2）
- 当前阶段是否已有对应 skill 可复用？（是 → 使用 skill；否 → 按标准文档执行并补充流程）

### 阶段出口标准

- 未完成文档闭环，不进入正式实现。
- 原型未确认，不进入真实接口与联调阶段。
- 契约未冻结，不进入数据库迁移或大范围后端实现。
- 验证不完整，不进入 PR 合并流程。

### 文档粒度原则

- 文档要满足"足够让 AI 和人类做下一步决策"，而不是追求长篇幅。
- 必要文档缺失时，先补最小占位内容，再继续实现。
- 可选文档只在复杂度确实需要时补充，不为了完整性而机械新增。
- 文档一旦承担契约作用，内容必须稳定、可验证、可追溯。

### 最小验证清单

- 关键文档已补齐且可追溯
- API/数据模型/交互一致
- 契约校验脚本已通过（如涉及 API）
- 至少一条可复现的验证步骤
- 若涉及 Agent 资产，`.agents/skills/` 与 `.claude/skills/` 已同步
- 若涉及项目入口规则，`AGENTS.md` 与 `CLAUDE.md` 已同步

---

## 原型驱动交付流程

### 适用场景

- 需求复杂、细节多，用户很难只看文档确认
- 管理后台、审批、工单、表单、运营台等交互型产品
- 用户会在看到页面后才补充关键细节
- 希望先快速验证流程与页面，再投入后端和集成成本

### 推荐阶段

1. 需求访谈与范围确认：先用 `docs-main` 记录目标、核心场景、边界与未决问题。
2. 前端原型验证：使用 `frontend-main`（原型模式）生成可演示 Demo，只用 Mock 数据，不接真实后端。
3. 用户确认与收口：基于 Demo 收集反馈，确认页面、字段、状态、交互和关键路径。
4. 契约化回写：将已确认内容回写到 `01-prd.md`、`05-ui-interaction-spec.md`、`06-data-model.md`、`07-api.md`、`09-test-scenarios.md`，必要时补 `04-state-machine.md`。
5. 正式实现：再进入 `database-main`、`backend-main`、`frontend-main`，完成真实接口、业务逻辑和联调。
6. 测试与验收（分层执行）：
  - 第一层：AI 跑后端集成测试（API 契约、业务逻辑、权限），不通过则阻断。
  - 第二层：AI 用 Playwright MCP 跑前后端连通性测试（完整业务流程、多角色、空数据状态），发现对接问题。
  - 第三层：用户手动验收（页面布局、视觉、交互体验）。

### 原型阶段的硬性规则

- 原型只用于需求确认，不视为正式实现完成。
- 原型阶段禁止为了演示而改动后端、数据库或对外 API 契约。
- 原型一旦被用户确认，必须先完成文档回写，再进入正式后端与联调开发。
- 原型页面中用于演示的假数据、占位逻辑、临时文案，在正式实现阶段必须清理或替换。

### 什么时候优先使用原型流程

- 用户反馈依赖"看见界面"才能做判断
- 页面结构、表单字段、状态切换比后端算法更复杂
- 当前最大风险是"做错需求"，而不是"实现难度太高"

### 什么时候不要先走原型流程

- 任务主要是后端基础设施、数据库迁移、任务调度、鉴权、安全或结算逻辑
- 风险核心在数据一致性、事务边界、权限模型，而不是页面交互
- 需求已经通过契约文档充分冻结，不需要再用界面探索

### 原型流程的风险控制

- 演示前必须说明"这是 Mock 原型，不代表后端已完成"
- 用户确认后必须先做契约化回写再进入正式实现
- 原型字段尽量贴近正式 API 命名，避免引入错误数据结构

---

## 测试策略（三层全覆盖：契约 / 集成 / 端到端）

**测试金字塔三大层**：
- **契约层**：L0a / L0b / L0c — 字段对不对
- **集成层**：L1（L1a + L1b）/ L1c — 后端跑得对不对
- **端到端层**：L2 / L3 — 用户用起来对不对

> L0a/L0b/L0c/L1a/L1b/L1c 是子项命名（向后兼容历史报告），不是独立的金字塔层。L0 页面清点是测试范围规划，不是测试本身。

测试按 `L0 → L0a/L0b → L0c → L1 → L1c → L2 → L3` 顺序执行，前一项不通过则后一项无意义：


| 层       | 测什么        | 怎么测                          | 谁做             | 触发时机       |
| ------- | ---------- | ---------------------------- | -------------- | ---------- |
| L0      | 页面清点与测试范围  | 扫描前端可达页面和 API 调用             | AI             | 测试启动时      |
| L0a/L0b | 请求/响应契约一致性 | 静态脚本对比前端字段 ↔ 后端 DTO          | AI / Hook / CI | API 变更前后   |
| L0c     | 响应快照校验     | 实际发请求，对比真实响应 vs 前端 interface | AI             | API 变更后    |
| L1      | 后端业务逻辑     | 集成测试（HTTP 请求 → 真实数据库）        | AI 生成 + CI 自动跑 | 每次后端提交     |
| L1c     | 数据质量       | JSONB / FK / 种子数据校验脚本        | AI / CI / 发布流程 | 种子或生产数据变更后 |
| L2      | 前后端连通性     | Playwright MCP 走完整业务流程       | AI 执行          | API 改动后    |
| L3      | 用户体验       | 页面级验收清单 + 手工查看               | 用户本人           | 前六层通过后     |


各层的驱动文档和详细执行规则见 `test-backend` / `test-frontend` skill。

> **09 与 10 的关系**：`09-test-scenarios.md` 定义"测什么"（场景清单），`10-e2e-test-spec.md` 定义"怎么测"（流程编排剧本）。

**L0 契约校验**

- 任何 API 变更必须先过 `testing/scripts/contract-check.ts`，再进入 L1。
- 重点捕获字段名不匹配、Controller 手动映射漏字段、前端 interface 漂移。

**L1 集成测试**

- 直接调 HTTP API，校验返回值、字段结构、数据库状态。
- 覆盖：状态机、权限、错误映射、级联影响、跨域链路。
- 后端默认以集成测试为主；仅复杂纯计算逻辑可单独补单元测试。
- 现有后端单元测试视为历史遗留资产，不作为新功能默认交付项；新增后端测试优先落到 L1 集成测试。

**L1c 数据质量**

- 校验种子数据、JSONB 结构和 FK 引用的完整性。
- 数据质量脚本默认放在 `testing/scripts/`。

**L2 AI + Playwright MCP**

- 在真实浏览器环境走完整业务流程。
- 不写 E2E 测试代码，通过 AI + MCP 直接执行。
- 使用 accessibility tree 定位元素（role/name），不依赖 data-testid。

**L3 人工验收**

- 页面布局、视觉效果、交互体验、极端数据展示。
- 验收清单放在 `testing/checklists/`。

### 协议级 / 客户端集成功能：必须用真实客户端跑（curl 不算）

**触发条件**（任一）：

- 实现 / 改动**外部协议**（MCP / OAuth / OpenID Connect / SAML / SCIM / LDAP / WebSocket / gRPC / SSE 等）
- 实现 / 改动需要**特定客户端 SDK** 配合的端点（Stripe webhook / Slack OAuth / Anthropic API tool use 等）
- 实现 / 改动**机器对机器集成**（webhook 接收方 / API 给 CI / 给外部 bot 调用）

**硬规则**：

- curl 看响应字段 / Postman 看 JSON 形状 / 写 fetch 跑 happy path —— **都不算端到端**。
- 必须用**该协议官方客户端的真实实现**完整跑一次握手 + 业务调用 + 错误路径，验证客户端**接受且能用**服务端响应。
- L1 集成测试可以 mock 客户端验业务逻辑；但 **L2 / L3 必须留一项"真客户端"验证步骤**，跑不通就算 PoC 不通过。
- 验证证据要落地：截图 / log / `claude mcp list` 等明确指出"客户端跑通"的输出，不能只写"已验证"。

**为什么这条要单列**：自创协议变体（如把 JSON-RPC 包成 `{ok, data}`）/ 漏实现 spec 必需方法（如 MCP `initialize`）/ 字段命名不一致 —— 这些**只用 curl 测全是绿的**，但接上真客户端就废。internal-app-platform 模块就因为 PoC 只用 curl 验收，整个 MCP 链路在真实 Claude Code 客户端上完全不可用，直到 2026-05-18 真跑通才暴露（详见 `.learnings/2026-05-18-mcp-controller-not-jsonrpc-compliant.md`）。

**不做的事**：

- 不写前端单元/组件测试（MCP 已覆盖前端逻辑验证）。
- 不把后端单元测试作为默认要求扩张到普通 CRUD / Controller / 强依赖数据库的 Service。
- 不以覆盖率数字替代关键流程跑通。

---

## 分支准入规则

### 保护分支

- `develop`、`staging`、`production` 全部属于保护分支。
- 三个保护分支均禁止直接推送与强制推送。
- 所有进入保护分支的变更必须通过 PR 合并，不允许绕过检查直接入主线。

### 分支职责

- `develop`：团队日常集成主线，允许通过 PR + 自动合并提升集成效率。
- `staging`：测试/预发布分支，只接受已在 `develop` 集成完成的发布候选变更。
- `production`：正式发布分支，只接受经 `staging` 验证通过的上线变更或紧急修复。

### 环境升级合并策略（FF-only）

`develop → staging → production` 是**环境指针推进**，不是 feature 集成，合并策略与 `feature/* → develop` 不同：

| 场景 | Merge style | 历史形态 |
|------|-------------|---------|
| `feature/* → develop` | `squash` | develop 上一个 commit 一个 feature，线性 |
| `develop → staging` | **`fast-forward-only`** | staging 指针 FF 到 develop 的某个 SHA |
| `staging → production` | **`fast-forward-only`** | production 指针 FF 到 staging 的某个 SHA |
| `hotfix/* → production` | `squash` + 回灌 develop | 紧急修复时破例，事后必须回灌 |

**为什么 FF-only**：
- 三条分支共享同一条线性历史，"prod 上是哪个 commit" / "staging 比 prod 多了什么" 一眼看清（`git log production..staging`）
- 回滚 = 把指针挪回旧 SHA，干净；不用挑 merge commit 还是 first-parent
- 不产生菱形合并图，bisect 干净
- staging/production 永远是 develop 的"前缀"，不会出现"staging 上有但 develop 上没有"的脏 commit

**强制约束**：
- staging / production 上**禁止出现 merge commit**（多父 commit）——除 hotfix 的 squash commit 外，全部应是从 develop 直接 FF 过来的祖先 commit
- 仓库级 merge style 配置：只保留 `squash`（默认，develop 用）+ `fast-forward-only`（staging/production 用），其它（`merge` / `rebase` / `rebase-merge`）已关闭以防误点
- **必须用 `scripts/ops/gitea promote uat|prod` CLI 触发合并，禁止 Gitea web UI 手点**（PR #383 事故复盘：UI 默认 merge style 是 squash，reviewer 误点造成 production 历史与 staging 分叉，后续 force-reset 修复。Gitea 不支持 per-target-branch 强制 merge style——CLI 是唯一兜底）

**CLI 用法**：

```bash
# 合并 develop → staging（UAT 升级）
gitea promote uat

# 合并 staging → production（生产升级）
gitea promote prod

# 预演不真合并（推荐先看一遍）
gitea promote uat --dry-run

# CI 未全绿紧急绕过（需在 PR body 写理由）
gitea promote prod --force-anyway
```

CLI 不变量（在 PR #384 落地）：
- `Do=fast-forward-only` 写死，无法被改成 squash
- base 不能领先 head（compare API `behind_by > 0` → 拒绝）
- CI 全绿是硬门槛（combined status 必须 `success`）
- 自动 self-approve（**例外**：env-promote PR 允许自合，因为是机械操作 + token 已限制谁能调）
- post-merge 校验 `base tip == head sha`，不等则 `E_POST_MERGE_DRIFT`
- 详见 `scripts/ops/gitea promote --help`

**FF 失败怎么办**：
- 如果点 FF merge 报"non-fast-forward"，说明 staging/production 上有 develop 没有的 commit（通常是 hotfix）——必须先把那个 commit 回灌到 develop，再从 develop 重新升级
- 不允许通过造 merge commit "绕过去"

**hotfix 例外**：
- 严重生产故障可走 `hotfix/* → production`（squash merge），事后**当天必须**开 `hotfix-backport/* → develop` PR 把同样的修复回灌到 develop，否则下次 `develop → staging` FF 会失败

### 合并门禁（按目标分支分层，不重复）

**PR → `develop`（L2 门禁，硬阻断）**
- `quality-gates / verify-agent-assets`（资产同步校验，原 agent-assets-check.yml 已并入）
- `quality-gates / build-check`（nest build + next build，自带 tsc；原 lint-and-type-check 已合并进来）
- `quality-gates / migration-file-count`（一个 PR 最多一个迁移目录）
- `quality-gates / contract-check`（L0a/L0b 请求/响应字段对齐）
- `quality-gates / backend-integration`（L1 集成测试 + L0c 响应快照同 job 内跑，复用 backend container）
- `ai-review / ai-review`（required，硬阻断；2026-05-11 转正，auto-eval 综合分 72.5% ≥ 70%）

> 说明：reverse-direction 触发已收敛——quality-gates.yml 不再 `push: develop` 重跑（原来跟 deploy 并行不阻断，等于事后告警），合并后由 `deploy-test.yml` 服务器自带 build 当门禁。

**PR → `staging`（L3 门禁，不重跑 L2 已过的检查）**
- `ai-review / ai-review`（mode=batch-summary，本批次合并风险）
- 人工 final approve（必需）
- 不重跑 L2：quality-gates.yml 重型 job 用 `if: base_ref == 'develop'` 自动 skip，仅保留 verify-agent-assets
- merge 后跑：全量 L1 跨模块回归 + 全量 L2 E2E + L1c (UAT 验收库)

**PR → `production`（L4 门禁，环境层 + 强制人工）**
- `ai-review / ai-review`（mode=release-risk，发布风险/回滚预案）
- `migration-risk-review`（耗时预估/锁表风险）
- 人工**强制** approve，且 reviewer ≠ PR 作者
- 准入还需：独立 CI 脱敏快照校验绿
- 部署前/后：env 校验 / 连通性 / smoke / 灰度监控（详见 `deploy-ops` skill）

**通用规则**
- 三个保护分支禁止直推与强推。
- `push` 上下文只用于分支更新后的巡检，不作为 PR 合并门禁。
- 标 ⏳ 待加 的 CI job 见 `.gitea/workflows/` 缺口列表。

### 推荐流程

1. 从 `develop` 拉出 `feature/`* 或 `bugfix/`* 分支开发。
2. 提交 PR 到 `develop`，检查通过后可启用 Auto Merge 自动合入（**squash** 模式）。
3. 需要提测时，跑 `gitea promote uat` — CLI 自动开 PR、self-approve、FF 合并到 staging。
4. `staging` 验证通过后，跑 `gitea promote prod` — 同上，FF 合并到 production。

### PR 描述

PR body 写作必须遵守 [`13-pr-description-spec.md`](./13-pr-description-spec.md)：v2 两层模板设计（上半部分核心叙事服务当下 reviewer 决策；下半部分回顾段服务半年后 retro / bisect / changelog）+ 六条元规则（含**必填 `Closes #N`** + **PR push 新 commit 后必须 PATCH body 反映最终状态**）+ 反例正例对照。模板位于 `.gitea/PULL_REQUEST_TEMPLATE.md`，仅 Gitea 网页创建 PR 时自动加载，API / CLI 创建需手动遵循结构。

### Commit 前自检顺序

`bash scripts/dev/ai-review-local.sh` → `/simplify` → `git commit`。前者跑 7 维度审视（契约面 / 数据迁移 / 测试覆盖 / 安全 / 文档一致性 / 高风险路径合规 / 代码逻辑）暴露方向性问题；后者跑 reuse / quality / efficiency 打磨细节。两者正交互补，**先架构纠偏，后细节打磨**，避免 simplify 修完代码再发现方向错。触碰契约面 / 高风险路径 / >10 文件 PR 强烈推荐跑 ai-review-local；小改动 / 文档 hotfix 可跳过。详见 `.agents/skills/code-review/SKILL.md`「本地前置模式」段。

### 并行开发建议

- **任何需求改动都必须在 slot 或命名 worktree 里做，不在主仓库**（池存在前提下）——claim 切换 0.5 秒，没理由留在主仓库做需求。详见 [`10-agent-pool.md` § 不变量](./10-agent-pool.md#不变量) 第 7 条。
- 同时存在 2 个及以上需求时，**默认用 agent pool**（常驻预热的 slot 池），不要在同一工作区频繁切分支。
- 一需求一分支，slot 是池里临时占的执行环境。
- 主仓库（`<repo>/`）只用作"基线 + 同步 develop + 跨 slot 协调"，不当作工作目录。例外：只读探索 / 协调 / 诊断（详见 10-agent-pool.md）

### 并行开发选择树（重要）

**两条路径**，按场景选：

```
开新任务时：
│
├─ 临时任务（< 1 周）/ AI 高频开 PR / 不需要语义命名
│   → agent pool（slot 池），见下文
│   → claim 一个 slot 即用，秒级
│
└─ 长期 feature（持续多周）/ 想要语义命名（如 asset-management）
    → setup-worktree.sh 创建命名 worktree
    → 自己起一个有意义的目录名长期常驻
```

| 资源 | 生命周期 | 例子 |
|------|---------|------|
| **agent pool 的 slot** | 临时占用，任务完释放回池 | `slot-1`、`slot-2`，每次 claim 用 |
| **命名 worktree** | 长期常驻 | `asset-management`、`recruitment` 等长期模块 |
| **分支（任务）** | 一次性，PR merge 后立即删 | `bugfix/<task>` / `feature/<task>` |

**为什么这样分**：环境创建昂贵（容器、依赖、env、Caddy 域名要 80-90 秒），分支创建便宜（一行命令）。
- pool 把"环境创建"成本一次性前置（`pool-init` ~5 分钟），后续每次任务 claim 是秒级（**实测 ~140× 加速**）
- 命名 worktree 适合那种"几周内反复回到同一个目录" 的长期 feature，名字本身是文档

**绝对禁忌**：
- 不要让一个分支跨越多个 PR（squash merge 会让历史混乱、需要 force-push）
- 不要让一个分支干两件事（review 不清、bisect 难、回滚连坐）
- **不在主仓库（`<repo>/`）改代码**——必须走选择树两条路径之一（slot 或命名 worktree）。即使是一行 typo / 文档调整 / hotfix，claim 切换 0.5 秒没借口跳过。详见 [`10-agent-pool.md` § 不变量](./10-agent-pool.md#不变量) 第 7 条

### Agent Pool（推荐入口）

- **机制原理 / 不变量 / 设计决策**：[`docs/standards/10-agent-pool.md`](./10-agent-pool.md)
- **工具参考（命令 / env / 调试 / 测试）**：[`scripts/dev/agent-pool/README.md`](../../scripts/dev/agent-pool/README.md)

```bash
# 一次性：初始化（默认 3 slot，约 5 分钟）
# setup-project skill 会默认跑这一步，新协作者一般不需要手工跑
bash scripts/dev/agent-pool/pool-init.sh

# 每次任务：claim → 干活 → release
eval "$(bash scripts/dev/agent-pool/agent-claim.sh feature/my-task)"
cd "${FFOA_AGENT_DIR}"
# ... edit / test / commit / push / PR ...
bash scripts/dev/agent-pool/agent-release.sh
```

**AI 入口约定**：每个新任务先尝试 `agent-claim`，**根据 exit code 决策**（不要把命令抛回给用户）：

| Exit | AI 应该 |
|---|---|
| 0 | `eval` 后开干 |
| 2 | 同分支冲突，问用户换分支或接手 |
| 3 | 池满，问扩池 / 等 / 走旧路 |
| 4 | 池未初始化（罕见，setup-project 默认初始化过），问"现在初始化吗？"（5 分钟） |
| 5 | 池被禁用（`FFOA_AGENT_POOL_ENABLED=false`），自动走旧路 |

**IDE 入口（VSCode multi-root + Remote-SSH）**：

`pool-init` / `pool-resize` / `agent-claim` / `agent-release` 自动维护
`<repo-parent>/<repo>.code-workspace` 文件，列 main + 全部 slot。本地 VSCode
通过 Remote-SSH 打开此文件，**单窗口同时看到 main + 全部 slot 的改动**——
多 agent 并行时一个 IDE 即可，不用开 N 个窗口。详见 README §「VSCode multi-root +
Remote-SSH 入口」。

**路径解析**：池根优先级 `$FFOA_AGENT_POOL_ROOT` > `<repo-parent>/<repo>-wt/.agent-pool`（新规则）> `<repo-parent>/ffworkspace-wt/.agent-pool`（legacy 兼容）> 默认按新规则建。详见 README §「路径解析顺序」。

**协作者友好**：
- 默认 size 3，资源占用约 9 GB 磁盘 + 200 MB 内存
- pool-init 跑前 pre-flight 检查磁盘 / RAM / 端口冲突
- 资源紧张机器（CI / 笔记本）：`FFOA_AGENT_POOL_ENABLED=false` 一票禁用，自动 fallback 到 `setup-worktree.sh`
- `pool-resize --size N` 可扩缩容；`pool-destroy` 可彻底卸池（同时删 `.code-workspace`）

### 命名 worktree（长期 feature）

**典型流程**（已有 `asset-management/` worktree 的前提下）：

```bash
cd ~/Code/ffworkspace-wt/asset-management
git fetch origin
git switch -c bugfix/<task> origin/develop   # 新分支基于最新 develop
# ...改代码、commit、push、PR、等 merge
git switch develop && git pull --ff-only origin develop
git branch -D bugfix/<task>                  # 立即删本地分支
```

**新建命名 worktree**：

```bash
bash scripts/dev/setup-worktree.sh \
  ~/Code/ffworkspace-wt/<name> feature/<branch>
```

`setup-worktree.sh` 会自动分配端口、起独立 PG/Redis 容器、装依赖、初始化 schema、灌种子、注入 Caddy 域名。一次约 80-90 秒。这条路径仍然是有效的，agent pool 没有取代它，只是给"高频临时任务"提供了更快的入口。

### Worktree / Slot 初始化

由 `start-feature` skill 自动完成判断（pool 已存在则 claim slot；无则提议 init pool 或走 setup-worktree.sh），AI 不需要手工跑命令也不应该让用户跑。

### 分支生命周期与四道防线

防止历史分支堆积成"垃圾抽屉"。每条防线针对不同的漏点：

| # | 防线 | 谁来做 | 命令 / 配置 |
|---|------|--------|-------------|
| 1 | 远端自动删 | Gitea 仓库设置 | Settings → Pull Requests → "Delete pull request branch after merge by default" |
| 2 | 本地 tracking ref 自动 prune | 每个开发者本机一次配置 | `git config --global fetch.prune true` |
| 3 | Merge 后立即删本地分支 | 开发者自觉 | `git branch -D <task>`（见上面流程末尾） |
| 4 | 周期性 sweep 兜底 | 周一早上跑一次 | `bash scripts/dev/sweep-stale-branches.sh` |

**关于第 4 道**：脚本默认 dry-run，先看会删谁；确认无误用 `--apply` 真删。**只删** upstream 显示 `: gone]` 的本地分支（远端已不存在 = 一定被 PR 合掉或人工删了），保护分支白名单硬编码（`develop`/`staging`/`production`/`chore/notes-rolling`）。

**squash merge 用户特有的坑**：`git branch --merged develop` 检测**不到**已 squash 合掉的分支（不是祖先），必须用 `: gone]` 信号判断。

### 可选：Caddy 域名映射（个人配置）

### 可选：Caddy 域名映射（个人配置）

`scripts/dev/setup-worktree.sh` 末尾有一段 **opt-in** 的 Caddy 注入逻辑：未设置 `FFOA_DEV_DOMAIN_BASE` 的开发者完全跳过这段，行为不变；设置了的开发者会自动获得一个公网 HTTPS 域名直接访问 worktree 内的 dev server，免去 SSH 端口转发的麻烦。

**适用场景**：用本地 SSH 到远端开发机工作、希望浏览器直接通过域名访问、需要稳定 URL 给 Playwright MCP / 移动端真机扫码测试。

**前置条件**（自备）：
1. 一个**自己的**域名 + 通配 DNS（例：`*.test.example.com` 指向开发机公网 IP）
2. 开发机上跑一个 Caddy 实例（建议用 Docker `caddy:2-alpine`，挂个 Caddyfile 进去）
3. Caddyfile 里至少能让 `host.docker.internal:<port>` 通到宿主机端口

**配置环境变量**（在 `~/.bashrc` / `~/.zshrc`）：

```bash
# 必填：个人域名根（不带子域）
export FFOA_DEV_DOMAIN_BASE=test.example.com
# 必填：Caddyfile 在宿主机上的路径（脚本会写入这里）
export FFOA_DEV_CADDY_FILE=$HOME/caddy-config/Caddyfile
# 必填：reload 命令（脚本会 eval 执行）
export FFOA_DEV_CADDY_RELOAD_CMD='docker exec caddy caddy reload --config /etc/caddy/Caddyfile'
```

配好后，下次跑 `setup-worktree.sh` 时会自动在 Caddyfile 里追加：

```
# >>> ffoa-worktree:<short-name>:<user> >>>
<short-name>.<user>.test.example.com {
    handle /api/* { reverse_proxy host.docker.internal:<be-port> }
    handle /health* { reverse_proxy host.docker.internal:<be-port> }
    handle { reverse_proxy host.docker.internal:<fe-port> }
}
# <<< ffoa-worktree:<short-name>:<user> <<<
```

**域名命名规则**：`<worktree-short-name>.<linux-user>.<FFOA_DEV_DOMAIN_BASE>`

`<linux-user>` 部分让多个开发者共享同一段 wildcard DNS 时也不会撞车（例如你叫 `chentao`，同事叫 `zhangsan`，各自的 `feature-x.chentao.test.example.com` 和 `feature-x.zhangsan.test.example.com` 互不影响）。

**清理 worktree**：用 `bash scripts/dev/cleanup-worktree.sh <path>`，会自动一并删 Caddy 块、Docker 容器（PostgreSQL / Redis）、git worktree。

**注意**：项目代码不持有任何特定开发者的域名 / 路径。整段逻辑通过 env 变量 opt-in，没配 env 的开发者运行 `setup-worktree.sh` 跟以前完全一样，零侵入。

---

## Skills 使用原则

### 为什么本文件不维护完整 skills 清单

- skills 会随着项目演进增减，直接写在工作流里容易失效。
- 工作流关注"阶段与交付"，skills 清单关注"有哪些可复用流程"。
- skills 清单只维护一份，能避免入口文档、工作流文档和实际目录长期漂移。

### 正确分工

- 工作流文档：定义阶段、决策点、交付物、验证要求。
- skills 清单：定义当前可用的 skill 及其用途。
- 具体 skill：定义某类任务该怎么执行。

### 什么适合技能化

- 代码评审、后端实现、数据库迁移、测试执行与报告、发布前检查

### 什么不适合技能化

- 项目全部规则总表、模块业务背景百科、长期稳定的架构说明

### 当前入口

- 共享 skills 清单：`/.agents/skills/README.md`
- Claude / Codex / Cursor 目录仅作为分发结果，不单独维护说明

---

## 持续优化机制

### 适用范围

- 文档结构与模板
- `AGENTS.md` / `CLAUDE.md` 入口规则
- skills 设计与技能清单
- scripts、hooks、CI 校验流程
- 测试与报告机制

### 触发条件

- 同类问题被重复解释或重复修复
- 某份文档长期无人使用，或维护成本明显高于价值
- 某个 skill 与实际工作流脱节
- 某个 hooks / scripts 无法有效阻止常见错误
- 团队在实际开发中已经形成更高效、更稳定的新做法

### 执行规则

1. 先明确当前问题、低效点或重复成本。
2. 说明为什么现状不再合适，以及更优方案带来的收益。
3. 评估影响范围：
  - 是否影响外部契约
  - 是否影响现有模块文档
  - 是否影响工具目录、hooks 或 CI
4. 影响全局规则或契约时，先确认再修改。
5. 修改后必须同步更新：
  - 权威文档
  - 相关 skill 或模板
  - 必要的 scripts / hooks / 测试报告

### 优化原则

- 优先删除无价值复杂度，而不是继续叠加规则。
- 优先收敛到单一事实源，避免多处重复定义。
- 优先把"口头经验"沉淀成文档、模板或自动化。
- 优先保留高频、高价值、可复用的流程。

---

## 故障 / bug 解决方法论

遇到 bug / 事故时，**强制按 3 层拆解**：表面症状 → 直接原因（层 2）→ 元根因（层 3，治理层问题）。

- 不许停在层 2。直接原因找到后必须追到层 3。
- 修复必须分两层并行：**应用层修复** + **工程化保险**（让同类问题再出现时能自动拦截）。
- 缺工程化保险 = 没真正修好 —— 靠 learning 和记忆约束的，是"靠人"不是"靠系统"。
- 任何 P0/P1 工单关闭，复盘必须填满 6 段模板，至少识别 1 个元根因，至少 1 条工程化保险。

完整方法论、复盘模板、强制要求详见 [`docs/standards/11-troubleshooting-methodology.md`](./11-troubleshooting-methodology.md)。

参考案例：[工单 #242](http://43.130.59.228/FFAIWorkspace/workspace/issues/242)（晚间打卡 401 → 5 元根因）。

---

## 通用工程 pattern

### Ratchet（棘轮）模式 —— 在 brownfield 引入新质量门禁

**适用场景**：想给项目加新质量检查（env 字段对齐 / lint rule / type strict / 测试覆盖率），但当前违规太多，硬开门禁会阻塞所有 PR。

**反模式**：要么硬开（所有 PR 立即挂，团队反弹后只能 disable），要么默默 silence（违规越积越多）。

**Ratchet 模式三件套**：

1. **当前违规 baseline 化**：把现状违规清单 commit 到 `scripts/ops/<check>-baseline.txt`，进 git，被 PR 审视
2. **CI 仅阻断"新增"违规**：`违规集合 = (代码现状) - (baseline)`，只看 delta
3. **棘轮只能往紧的方向走**：每次清理一项违规 = 在代码修一处 + 从 baseline 删一行；**禁止往 baseline 加行**

```
检查目标集合 A（如代码里所有 process.env.X）
模板声明集合 B（如 .env.example 里所有 key）
baseline 缓刑集合 G

missing  = (A - B) - G    ← 硬阻断
zombie   = B - A          ← 警告（模板列了代码不用的）
stale_G  = G - A          ← 警告（baseline 里代码已不引用，鼓励删）
```

**设计要点**：

- **baseline 进 git**（不像 `.env`）—— 新人偷偷加 baseline 绕过门禁时 reviewer 会看到
- **stale_baseline 也要警告** —— "代码已不引用，删一行就能收紧门禁"，让清理有正反馈
- **检查目标是代码 vs 模板**，不是代码 vs `.env`（本地 `.env` gitignored，CI 看不到）

**已落地例**：`scripts/ops/env-coverage-baseline.txt` + `scripts/ops/check-env-coverage.sh`。

**可移植场景**：lint rule (`.eslintrc-baseline.json`)、TypeScript strict (`tsconfig-strict-baseline.json`)、测试覆盖率（每模块当前比例 baseline，新代码必须 ≥ baseline）、安全规则（CodeQL alert baseline）等。

**反模式**：

- ❌ 一次性想把所有违规清干净再开门禁 → 永远开不起来
- ❌ baseline 不进 git → 新人偷偷加，门禁形同虚设
- ❌ 只看 `代码 - 模板`（绝对违规集），不引入 baseline → 第一天就阻塞

### 三层完工模型 —— 部署/CI 类 PR 的 L1/L2/L3 边界

任何触碰**部署 / CI / 服务器配置**的 PR，完工分三层，**L1 ≠ L2 ≠ L3**：

| 层 | 闭环依据 | 谁能保证 | 失败时谁修 |
|---|---|---|---|
| **L1 合并** | PR review + CI 全绿 + merge develop | reviewer + AI Review + CI workflow | PR 作者 |
| **L2 部署实测** | test → UAT → prod 三阶段实跑 + 实际依赖（PG / Redis / Temporal / Nginx）真生效 | 部署阶段触发的人 + 看监控的人 | hotfix / 紧急 PR |
| **L3 follow-up 收口** | 衍生工单 / TODO 全部 closed | follow-up 工单 owner | 各 owner 自己 |

**适用判定**（满足其一即按三层走）：

- 改 `scripts/deploy/` / `scripts/ops/` / `.gitea/workflows/deploy-*.yml`
- 改 `setup-production.sh` 或新机器初始化逻辑
- 改 Nginx / PM2 / Docker compose 生产配置面
- 任何"新机器 / 新容器首次跑"才能验证的兜底逻辑（citext / temporal namespace bootstrap / ssl-cert 等）

**纯代码 PR** 只走 L1；**部署 / CI PR** 必须独立追 L2；**任何 PR** 都可能产生 L3。

**工作方式**：

- 部署 / CI 主 PR 合并后**立刻**开一个"部署后实测"工单（标 `Type/L2-Verification`），不要 close 主 PR 等 L2 跑完——主 PR 关闭意味着 L1 完成，但 L2 责任独立追踪
- L3 follow-up 必须开**独立工单**，不要写在已 closed 的主 issue 评论里——评论会随 issue close 而 stale，失去追踪意义

**反模式**：

- ❌ "PR merge 了就算上线" → L1 = L2 错觉，prod 出问题没人盯
- ❌ "follow-up 记在主 issue 评论里"→ issue close 后无人追

---

## 何时更新本文档

出现以下情况时应更新：

- 新增或替换主要 AI 工具
- 入口文件、skills 管理方式或 hooks 策略变化
- 团队决定调整文档与自动化职责边界
- 现有流程无法支撑多人、多工具协作
- 开发阶段、测试策略或分支规则发生变化

