17 Commits

Author SHA1 Message Date
23ea8fdca5 feat: 融合 devflow-claude P0 批机制 (REQ-20260416-0017)
P0-1: SessionStart Hook — hooks/session-context.sh
  从分支名解析 REQ-ID,调 MCP API 查询需求详情注入 system-reminder

P0-2: PreToolUse Hook — hooks/pre-tool-confirm.sh
  拦截生产推送、force push、docker prod 容器操作、git reset --hard 等

P0-3: Release Draft 闸门设计文档 — docs/design/release-draft-gate.md
  完整架构 + 渐进式落地路径(拆 7 个子任务延后)
  附最小可用脚本 hooks/release-draft.sh 创建 Gitea draft release

P0-4: Memory 隔离规则 — 写入 req-prd / req-design / req-workflow
  禁止 auto-memory 污染模板产出物(章节结构、字段定义、文档结构)

P0-5: CLAUDE.md 架构检查 + 架构片段库
  dev-coding skill 执行前检查架构关键词
  新增 templates/claude-md-snippets/ 含 Go+Gin / React+AntD / Vue+Element /
  MCP+TS / generic 五套骨架

P0-6: /commit 分支保护自动化 — 新 skill dev-commit-plugin
  保护分支自动建功能分支 + Conventional Commits + REQ-XXX 自动关联

安装:
  bash hooks/install.sh

后续:
  P0-3 完整实现拆 7 个子任务(P0-3.1 ~ P0-3.7)
  建议先部署 hooks 跑 1-2 周观察,再推进 Release 机制落地
2026-04-16 21:02:29 +09:30
bfe3815626 fix(skill): 修复质量检查发现的引用问题
- req-workflow: req-dev → req-design (2处)
- req-design: changelog 标注"原名 req-dev"
- marketplace.json 重新生成 (44→46 plugins)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 17:47:01 +09:30
3706d7f32d feat(skill): REQ-20260406-0004 技能三层分离重构(7主线+16插件)
批次1: req-prd 瘦身 + req-design 重定位 + dev-coding 聚焦
批次2: dev-review 新建 + review-checklist 插件
批次3: dev-integration 新建 + req-compare 拆出
批次4: 插件完善 (req-research/db-migration/dev-scaffold/deploy-rollback)
批次5: 平台拆分 (dev-ios/dev-android/dev-mcp/dev-pda) + dev 分组更新
批次6: marketplace.json 32→44 plugins

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 17:44:08 +09:30
dongliang
31c2d5a474 feat(dev-deploy): SSH timeout + xcodegen cwd lessons (#11 #12) 2026-04-06 17:41:02 +09:30
dongliang
ccbdfd7eb3 feat(dev-cicd): docker exec health check + nginx mount lesson (#93 first green) 2026-04-06 13:49:15 +09:30
dongliang
f0e5735ffa feat(dev-cicd): CD deployment checklist + health check port mismatch lesson 2026-04-06 12:42:48 +09:30
dongliang
52b8c85b94 feat(dev-cicd): docker compose up --no-deps lesson 2026-04-06 11:53:38 +09:30
dongliang
0e24828a6d feat(dev-cicd): add docker compose pull scope + Docker Hub timeout lesson 2026-04-06 11:49:18 +09:30
dongliang
d564e6dbf9 feat(dev-cicd): add Docker context analysis + .dockerignore check
从实际 CI 失败中学到的经验:
- 缺 .dockerignore 导致 768MB context 传入(node_modules)
- ACR push denied 因镜像路径缺 namespace
- /cicd analyze 增加 .dockerignore + 凭据硬编码 + 镜像命名扫描

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 11:43:21 +09:30
dongliang
a58dc39795 feat: add dev-cicd skill + enhance dev-deploy
新增 dev-cicd(CI/CD 流水线设计/优化/排查):
- Gitea Actions 模板(Go/iOS/Web/Docker)
- Pipeline 优化(浅克隆/缓存/并发取消)
- 故障排查决策树(20+ 常见错误)
- 安全检查清单 + Runner 管理

增强 dev-deploy(部署执行):
- Docker Staging/Production 部署模板
- 部署前健康检查(证书/Docker/磁盘)
- 回滚策略(TestFlight/Docker/数据库)
- 部署监控(Feishu通知/ASC API)

技能总数: 28 (dev 分类: 7)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 11:10:13 +09:30
dongliang
b5f44ac6aa feat: add dev-deploy skill — iOS TestFlight deployment
新增部署技能,含 iOS TestFlight 完整部署流程:
- SSH 远程构建 + 无签名 Archive + Export 签名上传
- ASC API 补全合规/测试说明/版本关联
- 10 个坑的经验教训总结
- 一键部署脚本模板 + 检查清单

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 09:46:23 +09:30
b6bd4bbfed feat(req): 新增 /req ci 命令 + dev→review quality_gate 门禁说明
- req 技能新增 /req ci 命令规范(CI 检查与自动修复循环)
- 补充 dev→review 阶段 quality_gate 门禁说明
- req-workflow 流程概览增加 7.5 /req ci 步骤

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 13:19:55 +10:30
187f5621c9 feat(req): 部署门禁制度 — PDV 验收任务 + Deploy Gate 1-3
在 /req deploy 流程中增加部署后 E2E 验收(Post-Deploy Verification)门禁:
- 新增 verification linkRole 和【验收】任务命名规范
- Deploy Gate 1 健康检查 / Gate 2 PDV 任务完成 / Gate 3 证据完整
- PDV Playwright spec 模板(页面可达、菜单可见、API 连通)
- 同步更新 req-workflow、dev-test、e2e-testing 相关文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 09:34:08 +10:30
b9c808cce0 feat(req-test-gate): 集成 Harness Engineering 工程约束方法论
将项目级的 Ratchet/约定检测方法论融入 req-test-gate 技能,
通过 /req 流程三个节点自动触发(dev 环境检测、cr 约定建议、test Gate 0B),
无需手动记忆执行。

新增文档:harness-engineering.md、ratchet-pattern.md、convention-flow.md、
project-bootstrap.md 及 4 个模板(ratchet/convention 脚本、GATES.md、pre-commit)。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 11:34:42 +10:30
e3924e6b2b feat(skills): 新增 agent-browser 浏览器自动化技能
基于 Vercel agent-browser CLI,支持网页交互、E2E 冒烟测试、需求验收验证、前端开发验证和截图对比。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 16:07:04 +10:30
22107fa7b8 feat(req): 集成 Stitch 原型设计到需求工作流
新建 req-prototype 技能,支持基于 PRD 自动生成 Stitch UI 原型。
同步 req-review、req-workflow 技能到仓库,并更新 req、req-prd 中的
原型相关引用。

REQ-20260320-0005

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 23:42:24 +10:30
0724357ff4 feat(dev-test): 添加集成测试模板 + TG2 检测规则
- 新增 templates/go-integration-test.md 集成测试代码骨架模板
- SKILL.md 增加 TG2 集成测试检测:跨 handlers/middleware/routes 变更自动触发

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 14:28:44 +10:30
75 changed files with 7510 additions and 929 deletions

View File

@@ -47,6 +47,44 @@
],
"strict": false
},
{
"name": "db-migration-plugin",
"source": "./skills-dev/db-migration-plugin",
"description": "数据库变更方案插件。Migration 脚本生成、数据迁移策略、回滚方案。挂载在 design 阶段,涉及数据库变更时激活。",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "deploy-rollback-plugin",
"source": "./skills-dev/deploy-rollback-plugin",
"description": "回滚方案插件。部署后发现问题时的回滚策略、数据修复、灰度回退。挂载在 deploy 阶段。",
"version": "1.0.0",
"category": "devops",
"keywords": [
"devops",
"deployment",
"operations"
],
"strict": false
},
{
"name": "dev-android-plugin",
"source": "./skills-dev/dev-android-plugin",
"description": "Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。按需加载。",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-arch-plugin",
"source": "./skills-dev/dev-arch-plugin",
@@ -60,10 +98,127 @@
],
"strict": false
},
{
"name": "dev-cicd-plugin",
"source": "./skills-dev/dev-cicd-plugin",
"description": "Plugin for dev-cicd",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-coding-plugin",
"source": "./skills-dev/dev-coding-plugin",
"description": "Plugin for dev-coding",
"description": "软件编码开发技能。Go 后端 + Vue/React 前端编码实现,集成 ai-proj 任务管理。",
"version": "2.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-commit-plugin",
"source": "./skills-dev/dev-commit-plugin",
"description": "智能 /commit 命令:分支保护 + 自动建功能分支 + Conventional Commits 生成",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-deploy-plugin",
"source": "./skills-dev/dev-deploy-plugin",
"description": "Plugin for dev-deploy",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-integration-plugin",
"source": "./skills-dev/dev-integration-plugin",
"description": "前后端联调技能。API 契约验证、联调报告、纯后端需求自动跳过。对应 req 流程 integration 阶段。",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-ios-plugin",
"source": "./skills-dev/dev-ios-plugin",
"description": "iOS 开发插件。Swift/SwiftUI + MVVM 架构、TestFlight 部署、Xcode 构建。按需加载。",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-mcp-plugin",
"source": "./skills-dev/dev-mcp-plugin",
"description": "MCP Bridge 开发插件。TypeScript MCP 服务开发、Token 管理、HTTP 客户端模式。按需加载。",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-pda-plugin",
"source": "./skills-dev/dev-pda-plugin",
"description": "PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先模式。按需加载。",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-review-plugin",
"source": "./skills-dev/dev-review-plugin",
"description": "代码评审技能。五视角对抗性扫描法(攻击者/泄露者/并发者/边界者/依赖者CR 报告生成,独立于 req 工作流可单独使用。",
"version": "1.0.0",
"category": "development",
"keywords": [
"development",
"coding",
"workflow"
],
"strict": false
},
{
"name": "dev-scaffold-plugin",
"source": "./skills-dev/dev-scaffold-plugin",
"description": "模块脚手架插件。新建模块时自动生成分层代码骨架Model/Repository/Service/Handler/Route。挂载在 dev 阶段。",
"version": "1.0.0",
"category": "development",
"keywords": [
@@ -99,10 +254,48 @@
],
"strict": false
},
{
"name": "review-checklist-plugin",
"source": "./skills-dev/review-checklist-plugin",
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
"version": "1.0.0",
"category": "utility",
"keywords": [
"utility",
"tools"
],
"strict": false
},
{
"name": "req-compare-plugin",
"source": "./skills-req/req-compare-plugin",
"description": "对比式需求分析插件。系统平移、竞品借鉴、版本升级时的参考对象对比分析。挂载在 analysis 阶段。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-design-plugin",
"source": "./skills-req/req-design-plugin",
"description": "需求开发设计技能。PRD 到开发设计的转换API 契约、数据模型变更、任务拆分、风险评估。",
"version": "2.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-dev-plugin",
"source": "./skills-req/req-dev-plugin",
"description": "Plugin for req-dev",
"description": "[已废弃] 请使用 req-design-plugin。需求开发设计功能已迁移。",
"version": "1.0.0",
"category": "development",
"keywords": [
@@ -128,7 +321,46 @@
{
"name": "req-prd-plugin",
"source": "./skills-req/req-prd-plugin",
"description": "Plugin for req-prd",
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
"version": "2.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-prototype-plugin",
"source": "./skills-req/req-prototype-plugin",
"description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-research-plugin",
"source": "./skills-req/req-research-plugin",
"description": "需求调研插件。代码审计、数据库分析、现有功能调研。挂载在 analysis 阶段,需要深度调研时激活。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-review-plugin",
"source": "./skills-req/req-review-plugin",
"description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
@@ -141,7 +373,20 @@
{
"name": "req-test-gate-plugin",
"source": "./skills-req/req-test-gate-plugin",
"description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5,含前后端联调+视觉验证)、部署级验证(Deploy Gates)、持续回归(Regression)。",
"description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5)、部署级验证(Deploy Gates)、持续回归(Regression)、Harness Engineering 工程约束方法论Ratchet、约定建立、门禁层级。",
"version": "1.0.0",
"category": "productivity",
"keywords": [
"project-management",
"tasks",
"requirements"
],
"strict": false
},
{
"name": "req-workflow-plugin",
"source": "./skills-req/req-workflow-plugin",
"description": "需求完整工作流。从创建到归档的完整流程、Hook 自动同步、测试环境流程。",
"version": "1.0.0",
"category": "productivity",
"keywords": [

View File

@@ -0,0 +1,253 @@
# Release Draft 闸门机制 — 设计文档
**REQ**: REQ-20260416-0017 P0-3
**状态**: 设计阶段
**创建时间**: 2026-04-16
---
## 1. 背景
### 当前问题
ai-proj 当前 CI/CD 流程(`.gitea/workflows/build.yaml`
```
push 到 main → 自动 build 镜像 → 自动部署生产
```
**这个链路没有"最后一道人工闸门"**。merge develop→main 的 PR 一合并,生产就开始部署。一旦合并,只能事后回滚。
**典型事故场景**PR 评审时漏了某个改动merge 后立即推到线上5 分钟后发现问题,但已经影响用户 5 分钟。
### 借鉴方案
**devflow-claude `/req:release` 命令的核心做法:**
1. merge PR 不直接部署
2. 创建一个 **draft release**(草稿)
3. **需要人工在 Gitea/GitHub 平台点 "Publish" 按钮** 才触发部署
4. Draft 可以审查 SQL migration、回滚脚本、changelog 等"产物清单"
5. Publish 后才打 tag + 触发 build.yaml
---
## 2. 目标
- 在 merge main 和"真正部署"之间插入 **人工 publish 闸门**
- 提供 **release 产物清单预览**SQL migration / 回滚脚本 / changelog
- 支持 **一键回滚**(从 draft release 追溯回滚脚本)
- 与现有 ai-proj MCP 工具链集成
---
## 3. 架构设计
### 3.1 流程对比
**当前流程:**
```
[feat/xxx] → PR → merge develop → 测试
[develop] → PR → merge main → ✗ 立即触发 build.yaml → 生产部署
```
**新流程:**
```
[feat/xxx] → PR → merge develop → 测试
[develop] → PR → merge main → Gitea draft release待审查
人工 publish
tag 推送 + 触发 build.yaml → 生产部署
```
### 3.2 组件职责
| 组件 | 新增/改造 | 职责 |
|------|---------|------|
| **ai-proj backend** | 新增 | `/api/v1/releases` REST API创建 draft、publish、查询、回滚 |
| **mcp-task-bridge** | 新增工具 | `create_release_draft` / `publish_release` / `list_releases` / `get_release` / `rollback_release` |
| **Gitea Actions** | 改造 | `build.yaml` 触发条件改为 `release.published` 事件 |
| **`release` skill** | 新增 | AI 侧命令封装(`/release new`, `/release publish`, `/release rollback` |
| **release-draft.sh** | 新增脚本 | 本地命令行工具,用于在 CI 外手动创建 draft |
### 3.3 数据模型
**新增 `releases` 表:**
```sql
CREATE TABLE releases (
id SERIAL PRIMARY KEY,
display_id VARCHAR(64) UNIQUE NOT NULL, -- e.g. "RELEASE-20260416-001"
version VARCHAR(64) NOT NULL, -- e.g. "v1.2.0"
title VARCHAR(255) NOT NULL,
description TEXT,
status VARCHAR(32) NOT NULL, -- draft / published / rolled_back
git_base_ref VARCHAR(255) NOT NULL, -- e.g. previous tag "v1.1.9"
git_head_ref VARCHAR(255) NOT NULL, -- e.g. commit sha after merge
git_tag VARCHAR(64), -- 生成的 tagpublish 后才有
changelog_md TEXT NOT NULL, -- 自动生成的 changelog
sql_migration_paths TEXT[], -- 合并的 SQL 文件路径列表
sql_rollback_md TEXT, -- 回滚脚本
gitea_release_id BIGINT, -- Gitea 上的 release ID
gitea_release_url VARCHAR(512),
created_by INT REFERENCES users(id),
published_by INT REFERENCES users(id),
published_at TIMESTAMP,
rolled_back_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
```
### 3.4 API 设计
| Endpoint | 作用 | 权限 |
|----------|------|------|
| `POST /api/v1/releases/drafts` | 创建 draft release自动推导版本、生成 changelog | 开发者 |
| `POST /api/v1/releases/:id/publish` | 发布(推 tag、触发部署 | 需确认 |
| `GET /api/v1/releases` | 列表 | 所有人 |
| `GET /api/v1/releases/:id` | 详情 | 所有人 |
| `POST /api/v1/releases/:id/rollback` | 回滚到上一版本 | 管理员 |
### 3.5 Gitea 集成
**创建 draft release调 Gitea API**
```http
POST /api/v1/repos/{owner}/{repo}/releases
{
"tag_name": "v1.2.0",
"target_commitish": "main",
"name": "v1.2.0",
"body": "...<changelog>...",
"draft": true
}
```
**build.yaml 改造:**
```yaml
# Before
on:
push:
branches: [main]
# After
on:
release:
types: [published]
workflow_dispatch: # 保留手动触发
```
**关键变化**`release.published` 事件只在草稿被 publish 时触发merge main 不再自动触发。
---
## 4. 用户流程(典型场景)
### 4.1 开发者发版
```
1. 合并 PR 到 main照旧
2. 在 Claude Code 里:/release new
- AI 读 git log自动推导版本号
- 汇总 SQL migration
- 生成 changelog
- 生成回滚脚本
- 展示产物清单,等用户确认
3. 确认后MCP create_release_draft → 后端 API → Gitea draft
4. 收到 Slack/企微通知:"draft release v1.2.0 已创建,请审查"
5. 打开 Gitea 查看产物清单
6. 点 "Publish release" 按钮
7. CI/CD 自动触发 → 生产部署
```
### 4.2 回滚
```
1. /release rollback v1.2.0
2. MCP rollback_release → 后端执行回滚 SQL → 重新部署上一版本镜像
3. 记录到 releases 表status=rolled_back
```
---
## 5. 渐进式落地路径P0-3 拆分子任务)
由于 P0-3 完整实现涉及后端 + MCP + CI/CD + skill 四个层面,**不建议单会话完成**。拆分为:
| 子任务 | 范围 | 风险 |
|-------|------|------|
| **P0-3.1** | 后端 release model + migration | 低(只是建表) |
| **P0-3.2** | 后端 /api/v1/releases APIdraft + publish | 中 |
| **P0-3.3** | MCP 工具 create_release_draft / publish_release | 中 |
| **P0-3.4** | `release` skill 创建 | 低 |
| **P0-3.5** | Gitea draft release 集成 | 中 |
| **P0-3.6** | build.yaml 改为 release.published 触发 | **高**(影响所有人的发版流程) |
| **P0-3.7** | 回滚能力 | 中 |
**推荐落地节奏:**
- 先做 P0-3.1 ~ P0-3.5(构建基础能力)
- **保留旧 push-to-main 流程作为 fallback**
- 跑 2 周观察
- 再做 P0-3.6(切换 CI/CD 触发源)
- 最后 P0-3.7(回滚能力)
---
## 6. 风险与应对
### R1: build.yaml 触发源切换影响所有开发者
**影响**:目前大家习惯 "merge main 即部署",切换后需等 publish
**应对**
- 上线前 1 周发邮件 + 企微通知
- 提供手动触发workflow_dispatch作为应急入口
- 文档化新流程
### R2: 回滚脚本自动生成不够可靠
**影响**:复杂 migration如数据迁移的回滚无法自动推导
**应对**
- AI 只生成简单反向 DDLCREATE→DROP 等)
- 复杂情况标记 `⚠️ 需手工补全`
- 回滚 SQL 由人工审查后纳入 draft release
### R3: draft release 被忘记 publish
**影响**:功能开发完但生产没部署
**应对**
- 企微机器人每天检查超 24h 未 publish 的 draft发提醒
- 管理员 dashboard 显示 draft 列表
---
## 7. 验收标准
- [ ] `releases` 表创建migration 落地
- [ ] `/api/v1/releases/drafts` 创建 draft至少支持最小字段
- [ ] MCP `create_release_draft` 工具可用
- [ ] 能从 Claude Code 一键创建 Gitea draft release
- [ ] build.yaml 支持 `release.published` 触发
- [ ] 至少跑通 1 次完整流程draft → 人工 publish → 自动部署)
- [ ] 回滚脚本自动生成覆盖 >80% 的 DDL 场景
---
## 8. 参考
- devflow-claude: `plugins/req/commands/release.md`
- REQ-20260416-0017母需求
- 当前 build.yaml: `/Users/donglinlai/coding/qiudl/new-ai-proj/.gitea/workflows/build.yaml`
- Gitea Release API: https://docs.gitea.com/api/next/#tag/repository/operation/repoCreateRelease
---
## 9. 下一步行动
- [ ] 本文档提交评审
- [ ] 评审通过后拆 7 个子任务P0-3.1 ~ P0-3.7)并分别关联到 REQ-20260416-0017
- [ ] 从 P0-3.1(数据模型)开始实施

100
hooks/README.md Normal file
View File

@@ -0,0 +1,100 @@
# Claude Code Hooks
本目录包含 ai-proj-helper 体系的 Claude Code 钩子脚本。
**REQ-20260416-0017 P0 批 — 源自 devflow-claude 借鉴**
## 脚本清单
| 脚本 | 事件 | 作用 |
|------|------|------|
| `session-context.sh` | SessionStart | 从分支名解析 REQ-ID注入需求上下文到会话 |
| `pre-tool-confirm.sh` | PreToolUse (Bash) | 拦截生产发布、force push、docker 生产容器、reset --hard 等危险操作 |
## 安装(用户级,一次即可)
### 方式 1编辑 `~/.claude/settings.json`
```jsonc
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "/Users/donglinlai/coding/qiudl/ai-proj-helper/hooks/session-context.sh",
"timeout": 10
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/Users/donglinlai/coding/qiudl/ai-proj-helper/hooks/pre-tool-confirm.sh",
"timeout": 30
}
]
}
]
}
}
```
### 方式 2一键安装脚本
```bash
bash /Users/donglinlai/coding/qiudl/ai-proj-helper/hooks/install.sh
```
## 验证
### SessionStart hook
1. 切到一个带 REQ-ID 的分支:`git checkout feat/REQ-20260416-0017-xxx`
2. 打开新的 Claude Code 会话
3. 会话开头应看到 `# 需求上下文SessionStart Hook`
### PreToolUse hook
让 AI 尝试执行这些命令中的任一条,应弹出原生确认对话框:
- `git push origin main`
- `git push --force`
- `tea pr merge --base main`
- `docker rm ai_postgres_prod`
- `git reset --hard`
## 依赖
- `bash` (macOS / Linux 默认)
- `jq` (PreToolUse hook 需要,`brew install jq`)
- `python3` (SessionStart hook 解析 JSON)
- `curl` (SessionStart hook 调 MCP API)
## 自定义
### 修改 MCP API 地址
在项目根目录创建 `.ai-proj-env`
```bash
export AI_PROJ_API_BASE="https://api.ai-proj.example.com"
export AI_PROJ_MCP_KEY="your-mcp-api-key"
```
或设置全局环境变量。
### 拦截更多命令
编辑 `pre-tool-confirm.sh`,在 `REASON` 赋值的 elif 链中增加规则。
## 设计原则
1. **快速失败退出**:不处理的命令立即 `exit 0`,不影响性能
2. **非侵入性**:网络/依赖缺失时静默退出,不阻塞正常工作流
3. **可复现**hook 脚本跟随仓库分发,方便团队一致部署

81
hooks/install.sh Executable file
View File

@@ -0,0 +1,81 @@
#!/bin/bash
# install.sh
# 一键把 ai-proj-helper hooks 注册到 ~/.claude/settings.json
#
# 用法: bash hooks/install.sh
set -e
HOOKS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SETTINGS_FILE="$HOME/.claude/settings.json"
if ! command -v python3 >/dev/null 2>&1; then
echo "❌ 需要 python3用于合并 JSON"
exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
echo "⚠️ 未安装 jqPreToolUse hook 将无法正常工作"
echo " 请执行: brew install jq"
fi
mkdir -p "$HOME/.claude"
python3 << EOF
import json
import os
settings_file = "$SETTINGS_FILE"
hooks_dir = "$HOOKS_DIR"
# 读已有配置
if os.path.exists(settings_file):
with open(settings_file) as f:
data = json.load(f)
else:
data = {}
# 合并 hooks
hooks = data.setdefault("hooks", {})
# SessionStart
session_start = hooks.setdefault("SessionStart", [])
session_cmd = f"{hooks_dir}/session-context.sh"
already_registered = any(
any(h.get("command") == session_cmd for h in entry.get("hooks", []))
for entry in session_start
)
if not already_registered:
session_start.append({
"hooks": [{"type": "command", "command": session_cmd, "timeout": 10}]
})
print("✅ 注册 SessionStart hook")
else:
print("⏭️ SessionStart hook 已存在")
# PreToolUse (Bash)
pre_tool = hooks.setdefault("PreToolUse", [])
pre_cmd = f"{hooks_dir}/pre-tool-confirm.sh"
already_registered = any(
entry.get("matcher") == "Bash" and any(h.get("command") == pre_cmd for h in entry.get("hooks", []))
for entry in pre_tool
)
if not already_registered:
pre_tool.append({
"matcher": "Bash",
"hooks": [{"type": "command", "command": pre_cmd, "timeout": 30}]
})
print("✅ 注册 PreToolUse (Bash) hook")
else:
print("⏭️ PreToolUse hook 已存在")
# 写回
with open(settings_file, "w") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
print(f"\n📝 已更新: {settings_file}")
print("\n下一步")
print(" 1. 重启 Claude Code 会话")
print(" 2. 切到含 REQ-ID 的分支测试 SessionStart hook")
print(" 3. 让 AI 尝试 'git push origin main' 测试 PreToolUse hook")
EOF

94
hooks/pre-tool-confirm.sh Executable file
View File

@@ -0,0 +1,94 @@
#!/bin/bash
# pre-tool-confirm.sh
# PreToolUse Hook: 拦截危险操作,强制原生确认对话框
#
# 输入格式stdin JSON
# { "tool_name": "Bash", "tool_input": { "command": "..." } }
#
# 输出格式stdout JSON
# { "hookSpecificOutput": { "hookEventName": "PreToolUse",
# "permissionDecision": "ask",
# "permissionDecisionReason": "..." } }
#
# 安装方式:在 ~/.claude/settings.json 配置
# hooks.PreToolUse:
# - matcher: "Bash"
# hooks:
# - type: command
# command: "<path>/hooks/pre-tool-confirm.sh"
# timeout: 30
#
# 参考devflow-claude confirm-before-commit.sh + ai-proj memory 规则
# REQ-20260416-0017 P0-2
set -e
INPUT=$(cat)
if ! command -v jq >/dev/null 2>&1; then
# 没有 jq 就不处理
exit 0
fi
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
if [ -z "$COMMAND" ]; then
exit 0
fi
REASON=""
# ============ 1. 生产分支推送 ============
if echo "$COMMAND" | grep -qE '\bgit\s+push\b.*\b(origin\s+)?(main|master)\b'; then
REASON="⚠️ 即将推送到 main/master 生产分支。确认已过 PR 评审?"
# ============ 2. 强制推送 ============
elif echo "$COMMAND" | grep -qE '\bgit\s+push\b.*(--force|--force-with-lease|-f\b)'; then
REASON="⛔ 危险force push 会覆盖远程历史,可能丢失他人提交。确认继续?"
# ============ 3. tea pr merge --base main ============
elif echo "$COMMAND" | grep -qE '\btea\s+pr\s+merge\b.*--base\s+main\b'; then
REASON="⚠️ 即将合并 PR 到 main 分支,合并后将触发生产部署。确认 PR 已测试?"
# ============ 4. docker rm/stop 生产容器 ============
elif echo "$COMMAND" | grep -qE '\bdocker\s+(rm|stop|kill)\b.*\b(ai_postgres_prod|ai_backend_prod|ai_frontend_prod|ai_redis_prod)\b'; then
REASON="⛔ 危险:即将停止/删除生产容器2026-04-05 曾因此宕机 15 分钟。确认是灾难恢复?"
# ============ 5. docker rm/stop 其他 prod 相关 ============
elif echo "$COMMAND" | grep -qE '\bdocker\s+(rm|stop|kill)\b.*_prod\b'; then
REASON="⚠️ 即将停止/删除含 _prod 的容器。确认是生产环境?"
# ============ 6. git reset --hard / clean -fd ============
elif echo "$COMMAND" | grep -qE '\bgit\s+reset\s+--hard\b'; then
REASON="⚠️ git reset --hard 会丢弃所有未提交改动。确认继续?"
elif echo "$COMMAND" | grep -qE '\bgit\s+clean\s+.*-f'; then
REASON="⚠️ git clean -f 会删除未跟踪文件。确认继续?"
# ============ 7. rm -rf / 系统路径 ============
elif echo "$COMMAND" | grep -qE '\brm\s+.*-[rf]+.*\s+(/|/\*|~|\$HOME)'; then
REASON="⛔ 危险rm -rf 指向系统根或家目录。确认继续?"
# ============ 8. ssh 生产服务器 + 破坏性命令 ============
elif echo "$COMMAND" | grep -qE 'ssh\s+\S*prod\S*.*\b(rm|drop|truncate|delete)\b'; then
REASON="⛔ 危险:在生产服务器执行破坏性命令。确认继续?"
# ============ 9. psql/mysql 生产数据库 + DROP/TRUNCATE/DELETE ============
elif echo "$COMMAND" | grep -qiE '(psql|mysql).*prod.*\b(DROP|TRUNCATE|DELETE FROM)\b'; then
REASON="⛔ 危险:生产数据库 DROP/TRUNCATE/DELETE。确认已备份"
# ============ 10. MCP advance_delivery_stage force=true ============
# 这种会走 MCP 而不是 Bash本 hook 不好拦,留给另一个 matcher 处理
fi
if [ -n "$REASON" ]; then
jq -n --arg reason "$REASON" '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "ask",
permissionDecisionReason: $reason
}
}'
else
exit 0
fi

161
hooks/release-draft.sh Executable file
View File

@@ -0,0 +1,161 @@
#!/bin/bash
# release-draft.sh
# 最小可用版:从本地 git 仓库创建 Gitea draft release
#
# 用法:
# export GITEA_TOKEN=$(bw get password "Gitea - qiudl Token")
# bash release-draft.sh v1.2.0 [--from v1.1.9]
#
# 输出: 创建的 draft release URL待人工 publish
# REQ-20260416-0017 P0-3 最小可用脚本
set -e
VERSION="$1"
if [ -z "$VERSION" ]; then
echo "❌ 用法: $0 <version> [--from <previous_tag>]"
exit 1
fi
FROM_TAG=""
if [ "$2" = "--from" ]; then
FROM_TAG="$3"
fi
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "❌ 不在 git 仓库内"
exit 1
fi
REPO_SLUG=$(git remote get-url origin 2>/dev/null | \
sed -E 's|.*[:/]([^/]+/[^/]+)\.git$|\1|' | \
sed -E 's|.*[:/]([^/]+/[^/]+)$|\1|')
if [ -z "$REPO_SLUG" ]; then
echo "❌ 无法从 git remote 推断 OWNER/REPO"
exit 1
fi
if [ -z "$GITEA_TOKEN" ]; then
echo "❌ 需要 GITEA_TOKEN 环境变量"
echo " export GITEA_TOKEN=\$(bw get password 'Gitea - qiudl Token')"
exit 1
fi
GITEA_URL="${GITEA_URL:-https://gitea.pipexerp.com}"
# 推断 from
if [ -z "$FROM_TAG" ]; then
FROM_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
fi
TO_REF="HEAD"
# 生成 changelog 内容
echo "📋 生成 changelog..."
CHANGELOG=""
if [ -n "$FROM_TAG" ]; then
COMMITS=$(git log --pretty=format:'- %s (%h)' "${FROM_TAG}..${TO_REF}" 2>/dev/null || echo "")
else
COMMITS=$(git log --pretty=format:'- %s (%h)' "${TO_REF}" 2>/dev/null || echo "")
fi
if [ -z "$COMMITS" ]; then
echo "⚠️ 无 commit放弃"
exit 1
fi
# 按类型分组
FEATS=$(echo "$COMMITS" | grep -iE 'feat(\(|:)|新功能' || true)
FIXES=$(echo "$COMMITS" | grep -iE 'fix(\(|:)|修复' || true)
CHORES=$(echo "$COMMITS" | grep -iE 'chore(\(|:)' || true)
OTHERS=$(echo "$COMMITS" | grep -vE 'feat(\(|:)|fix(\(|:)|chore(\(|:)|新功能|修复' || true)
CHANGELOG="## 发布内容
**版本**: \`${VERSION}\`
**区间**: \`${FROM_TAG:-init}..${TO_REF}\`
"
if [ -n "$FEATS" ]; then
CHANGELOG="${CHANGELOG}### 新功能
${FEATS}
"
fi
if [ -n "$FIXES" ]; then
CHANGELOG="${CHANGELOG}### Bug 修复
${FIXES}
"
fi
if [ -n "$CHORES" ]; then
CHANGELOG="${CHANGELOG}### 杂项
${CHORES}
"
fi
if [ -n "$OTHERS" ]; then
CHANGELOG="${CHANGELOG}### 其他
${OTHERS}
"
fi
CHANGELOG="${CHANGELOG}
---
⚠️ **这是 draft release**,审查无误后点击 'Publish release' 按钮才会触发生产部署。
📋 审查要点:
- [ ] 所有改动已过 PR 评审
- [ ] SQL migration 已验证(如有)
- [ ] 回滚方案已确认(如有)
- [ ] 生产环境准备就绪"
# 创建 draft release
echo "🚀 创建 Gitea draft release..."
BODY_JSON=$(python3 -c "
import json
print(json.dumps({
'tag_name': '$VERSION',
'target_commitish': 'main',
'name': '$VERSION',
'body': '''$CHANGELOG''',
'draft': True,
'prerelease': False,
}))
")
RESP=$(curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$BODY_JSON" \
"${GITEA_URL}/api/v1/repos/${REPO_SLUG}/releases")
HTML_URL=$(echo "$RESP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('html_url',''))" 2>/dev/null)
if [ -n "$HTML_URL" ]; then
echo "✅ Draft release 已创建"
echo "🔗 $HTML_URL"
echo ""
echo "⏭️ 下一步:"
echo " 1. 打开链接审查产物清单"
echo " 2. 确认无误后点 'Publish release' 按钮"
echo " 3. CI/CD 将自动触发生产部署"
else
echo "❌ 创建失败"
echo "$RESP" | head -20
exit 1
fi

130
hooks/session-context.sh Executable file
View File

@@ -0,0 +1,130 @@
#!/bin/bash
# session-context.sh
# SessionStart Hook: 会话启动时自动注入需求上下文
#
# 从当前 Git 分支名解析 REQ-ID调用 ai-proj MCP API 查询需求详情,
# 把标题 / 状态 / delivery_stage / reviewer / 进行中需求数注入 system-reminder。
#
# 安装方式:
# 在 ~/.claude/settings.json 的 hooks.SessionStart 配置:
# {
# "command": "/Users/donglinlai/coding/qiudl/ai-proj-helper/hooks/session-context.sh",
# "timeout": 10
# }
#
# 参考devflow-claude 同名脚本 + ai-proj MCP 适配
# REQ-20260416-0017 P0-1
set -e
# 仅在 git 仓库内执行
if ! git rev-parse --git-dir >/dev/null 2>&1; then
exit 0
fi
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
if [ -z "$REPO_ROOT" ]; then
exit 0
fi
cd "$REPO_ROOT"
# ============ 1. 当前分支 → REQ ID ============
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo "")
REQ_ID=""
if [ -n "$BRANCH" ]; then
# 匹配 feat/REQ-20260416-0017-xxx / fix/REQ-20260416-0017 / feature/req-20260416-0017
REQ_ID=$(echo "$BRANCH" | grep -oiE 'REQ-[0-9]{8}-[0-9]{4}' | head -1 | tr '[:lower:]' '[:upper:]')
fi
# ============ 2. 无 REQ 时仅输出分支信息(静默退出条件) ============
if [ -z "$REQ_ID" ]; then
# 只要不在 main/develop 上就提示一下
case "$BRANCH" in
main|master|develop|"") exit 0 ;;
esac
echo "# 会话上下文"
echo ""
echo "- 当前分支: \`${BRANCH}\`(未检测到 REQ ID"
exit 0
fi
# ============ 3. 查询 MCP API ============
# MCP API 通过 localhost:8080 直连ai-proj 本地后端)或 ai-proj-prod
# 这里优先读项目根的 .ai-proj-env 决定环境
API_BASE="${AI_PROJ_API_BASE:-}"
API_TOKEN="${AI_PROJ_MCP_KEY:-}"
if [ -f "$REPO_ROOT/.ai-proj-env" ]; then
# shellcheck disable=SC1091
source "$REPO_ROOT/.ai-proj-env"
fi
if [ -z "$API_BASE" ]; then
# 默认走本地 dev
API_BASE="http://localhost:8080"
fi
# 查询需求
RESP=""
if command -v curl >/dev/null 2>&1; then
if [ -n "$API_TOKEN" ]; then
RESP=$(curl -s --max-time 3 -H "X-MCP-API-Key: $API_TOKEN" \
"${API_BASE}/api/v1/mcp/requirements/by-display-id/${REQ_ID}" 2>/dev/null || echo "")
else
RESP=$(curl -s --max-time 3 \
"${API_BASE}/api/v1/mcp/requirements/by-display-id/${REQ_ID}" 2>/dev/null || echo "")
fi
fi
# ============ 4. 解析并输出 ============
echo "# 需求上下文SessionStart Hook"
echo ""
echo "- 分支: \`${BRANCH}\`"
echo "- 需求: **${REQ_ID}**"
if [ -n "$RESP" ] && command -v python3 >/dev/null 2>&1; then
# 尝试用 python 解析
PARSED=$(python3 -c "
import sys, json
try:
d = json.loads('''$RESP''')
data = d.get('data', {})
if not data:
sys.exit(0)
title = data.get('title', '?')
status = data.get('status', '?')
stage = data.get('delivery_stage', '?')
priority = data.get('priority', '?')
project = data.get('project_name', '?')
print(f'title={title}')
print(f'status={status}')
print(f'stage={stage}')
print(f'priority={priority}')
print(f'project={project}')
except Exception:
pass
" 2>/dev/null)
if [ -n "$PARSED" ]; then
TITLE=$(echo "$PARSED" | grep '^title=' | sed 's/^title=//')
STATUS=$(echo "$PARSED" | grep '^status=' | sed 's/^status=//')
STAGE=$(echo "$PARSED" | grep '^stage=' | sed 's/^stage=//')
PRIORITY=$(echo "$PARSED" | grep '^priority=' | sed 's/^priority=//')
PROJECT=$(echo "$PARSED" | grep '^project=' | sed 's/^project=//')
[ -n "$TITLE" ] && echo "- 标题: ${TITLE}"
[ -n "$PROJECT" ] && echo "- 项目: ${PROJECT}"
[ -n "$STATUS" ] && echo "- 状态: ${STATUS}"
[ -n "$STAGE" ] && echo "- 交付阶段: ${STAGE}"
[ -n "$PRIORITY" ] && echo "- 优先级: ${PRIORITY}"
else
echo "- 📡 MCP API 响应为空或未授权API_BASE=${API_BASE}"
fi
else
echo "- ⚠️ 无法连接 MCP API${API_BASE}),仅显示分支信息"
fi
echo ""
echo "💡 相关命令:\`/req get ${REQ_ID}\` 查看详情 · \`/commit\` 智能提交"

View File

@@ -0,0 +1,8 @@
{
"name": "agent-browser-plugin",
"description": "浏览器自动化技能。用于网页交互、E2E冒烟测试、需求验收验证、前端开发验证、截图对比。基于 Vercel agent-browser CLI。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,186 @@
---
name: agent-browser
description: 浏览器自动化技能。用于网页交互、E2E冒烟测试、需求验收验证、前端开发验证、截图对比。基于 Vercel agent-browser CLI。
---
# agent-browser
浏览器自动化 CLI专为 AI Agent 设计。当用户需要与网页交互时使用:导航页面、填写表单、点击按钮、截图、提取数据、测试 Web 应用、自动化浏览器任务。
当用户提到以下关键词时自动激活浏览器自动化、打开网页、截图、网页测试、冒烟测试、E2E 验证、页面检查、agent-browser。
## 前置条件
```bash
npm i -g agent-browser # 安装 CLI
agent-browser install # 下载 Chrome
```
---
## 核心工作流snapshot-ref 模式)
1. **导航** 到 URL
2. **snapshot** 获取可交互元素(返回 `@e1`, `@e2` 等引用)
3. **交互** 使用元素引用
4. **重新 snapshot** DOM 变化后刷新引用
```bash
agent-browser open https://example.com/form
agent-browser snapshot -i
agent-browser fill @e1 "user@example.com"
agent-browser click @e3
agent-browser wait --load networkidle
```
---
## 命令参考
### 导航与控制
- `open <url>` 打开网页
- `goto <url>` 在会话内跳转
- `close` 关闭浏览器
- `wait <condition>` 等待元素/网络/JS 条件
### 页面检查
- `snapshot -i` 获取可交互元素及引用(推荐)
- `snapshot` 完整无障碍树
- `get text|html|value @e1` 提取元素内容
- `get title|url` 获取页面标题/URL
- `screenshot [path]` 截图
- `screenshot --annotate` 带元素标注的截图
### 交互操作
- `click @e1` / `dblclick @e1` 单击/双击
- `fill @e1 "text"` 清空并输入
- `type @e1 "text"` 追加输入
- `select @e1 "option"` 下拉选择
- `check @e1` 勾选/取消勾选
- `press Enter` 按键
- `hover @e1` 悬停
- `scroll down 500` 滚动
- `upload @e1 /path` 上传文件
- `drag @e1 @e2` 拖放
### 高级功能
- `eval 'code'` 执行 JavaScript
- `diff snapshot` 对比前后页面状态
- `set viewport 1920 1080` 设置视口
- `set device "iPhone 14"` 移动端模拟
- `find role <role> click --name "Label"` 语义定位器
- `network mock <pattern> --body '...'` 网络请求模拟
- `cookies get/set/clear` Cookie 管理
- `storage get/set/clear` localStorage 管理
---
## 认证与会话持久化
### Auth Vault推荐
```bash
agent-browser auth save myapp
agent-browser open https://myapp.com --auth myapp
```
### 持久化 Profile
```bash
agent-browser open https://site.com --profile ~/.myapp-profile
```
### 命名会话
```bash
agent-browser open https://site.com --session-name myapp
```
### 状态文件
```bash
agent-browser open https://site.com --state ./auth.json --save-state
```
---
## 命令链式调用
不需要中间输出时用 `&&` 串联:
```bash
agent-browser open https://example.com && \
agent-browser wait --load networkidle && \
agent-browser screenshot page.png
```
需要解析输出(如 snapshot 获取 ref时分开执行。
---
## 与其他技能结合
### 结合 dev-testE2E 冒烟测试)
在 dev-test 的 Gate 4E2E 冒烟测试)中使用:
```bash
# 1. 打开本地前端
agent-browser open http://localhost:3000 --session-name e2e-test
# 2. 验证页面加载
agent-browser snapshot -i
agent-browser screenshot /tmp/e2e-home.png
# 3. 测试登录流程
agent-browser fill @e1 "admin@example.com"
agent-browser fill @e2 "password"
agent-browser click @e3
agent-browser wait --load networkidle
# 4. 验证登录成功
agent-browser get title # 应包含 "Dashboard"
agent-browser screenshot /tmp/e2e-dashboard.png
# 5. 清理
agent-browser close
```
### 结合 req需求验收验证
PRD 评审后实际操作验证需求是否实现:
```bash
# 根据 PRD 验收标准逐项检查
agent-browser open http://localhost:3000/feature-page
agent-browser snapshot -i
# 按验收标准操作对应元素...
agent-browser screenshot /tmp/req-verify.png
```
### 结合 dev-coding前端开发即时验证
开发完组件后立即打开页面验证:
```bash
agent-browser open http://localhost:3000/new-page
agent-browser snapshot -i # 检查渲染的元素
agent-browser screenshot --annotate /tmp/dev-check.png # 带标注截图
```
### 结合 ops-tools部署后验证
部署后快速检查页面是否正常:
```bash
agent-browser open https://ai.pipexerp.com
agent-browser wait --load networkidle
agent-browser get title
agent-browser screenshot /tmp/deploy-check.png
agent-browser close
```
---
## 注意事项
- **Ref 生命周期**:导航或 DOM 变化后引用失效,必须重新 snapshot
- **超时**:默认 25 秒,通过 `AGENT_BROWSER_DEFAULT_TIMEOUT` 环境变量调整
- **会话隔离**:用 `--session-name` 实现并行自动化
- **安全**:支持域名白名单、操作策略、内容边界
- **输出格式**:用 `--json` 获取机器可读输出

View File

@@ -0,0 +1,6 @@
{
"name": "db-migration-plugin",
"description": "数据库变更方案插件。Migration 脚本生成、数据迁移策略、回滚方案。挂载在 design 阶段,涉及数据库变更时激活。",
"version": "1.0.0",
"author": { "name": "qiudl" }
}

View File

@@ -0,0 +1,105 @@
---
name: db-migration
description: 数据库变更方案插件。Migration 脚本生成、数据迁移策略、回滚方案。挂载在 design 阶段,涉及数据库变更时由 req-design 推荐激活。
---
# 数据库变更方案插件 (db-migration)
## 概述
当需求涉及数据库结构变更时使用,确保变更安全、可回滚。
**触发条件**
- 新增/修改/删除表或字段
- 数据迁移(旧数据转换)
- 索引优化
## Migration 规范
### 文件命名
```
backend/migrations/YYYYMMDDHHMMSS_description.up.sql # 正向迁移
backend/migrations/YYYYMMDDHHMMSS_description.down.sql # 回滚迁移
```
### 安全规则
| 操作 | 风险等级 | 注意事项 |
|------|---------|---------|
| ADD COLUMN (nullable) | 低 | 安全,无锁表 |
| ADD COLUMN (NOT NULL + DEFAULT) | 中 | PG 12+ 不锁表,旧版本锁表 |
| DROP COLUMN | 高 | 确认无代码引用,先标记废弃 |
| ALTER COLUMN TYPE | 高 | 可能锁表,大表慎用 |
| ADD INDEX | 中 | 使用 CONCURRENTLY 避免锁表 |
| DROP TABLE | 极高 | 必须确认无依赖 |
### Migration 模板
**新增表**
```sql
-- up.sql
CREATE TABLE IF NOT EXISTS xxx (
id BIGSERIAL PRIMARY KEY,
tenant_id BIGINT NOT NULL,
-- 业务字段
name VARCHAR(255) NOT NULL,
status VARCHAR(50) NOT NULL DEFAULT 'active',
-- 审计字段
created_by BIGINT,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMP
);
CREATE INDEX idx_xxx_tenant_id ON xxx(tenant_id);
CREATE INDEX idx_xxx_deleted_at ON xxx(deleted_at);
-- down.sql
DROP TABLE IF EXISTS xxx;
```
**新增字段**
```sql
-- up.sql
ALTER TABLE xxx ADD COLUMN yyy VARCHAR(255);
-- 如果需要索引
CREATE INDEX CONCURRENTLY idx_xxx_yyy ON xxx(yyy);
-- down.sql
DROP INDEX IF EXISTS idx_xxx_yyy;
ALTER TABLE xxx DROP COLUMN IF EXISTS yyy;
```
**数据迁移**
```sql
-- up.sql
-- 1. 先添加新字段
ALTER TABLE xxx ADD COLUMN new_field VARCHAR(255);
-- 2. 迁移数据
UPDATE xxx SET new_field = old_field WHERE new_field IS NULL;
-- 3. 添加约束(数据迁移完成后)
ALTER TABLE xxx ALTER COLUMN new_field SET NOT NULL;
-- down.sql
ALTER TABLE xxx ALTER COLUMN new_field DROP NOT NULL;
ALTER TABLE xxx DROP COLUMN IF EXISTS new_field;
```
## 大表变更策略
当表数据量 > 100 万行时:
1. **添加索引**:必须使用 `CREATE INDEX CONCURRENTLY`
2. **修改字段类型**:分步执行(新增列→迁移数据→切换引用→删除旧列)
3. **添加 NOT NULL**:先添加 DEFAULT再 SET NOT NULL
4. **数据迁移**:分批处理,每批 1000-10000 行
## 回滚检查
每个 Migration 必须有可执行的 down.sql
- [ ] down.sql 存在且语法正确
- [ ] down.sql 可以完全撤销 up.sql 的变更
- [ ] down.sql 不会丢失业务数据(除非是 DROP TABLE

View File

@@ -0,0 +1,6 @@
{
"name": "deploy-rollback-plugin",
"description": "回滚方案插件。部署后发现问题时的回滚策略、数据修复、灰度回退。挂载在 deploy 阶段。",
"version": "1.0.0",
"author": { "name": "qiudl" }
}

View File

@@ -0,0 +1,102 @@
---
name: deploy-rollback
description: 回滚方案插件。部署后发现问题时的回滚策略和执行步骤。挂载在 deploy 阶段,部署出问题时激活。
---
# 回滚方案插件 (deploy-rollback)
## 概述
当生产部署后发现问题时,提供结构化的回滚决策和执行步骤。
**触发条件**
- 部署后健康检查失败
- 部署后用户报告问题
- 部署后监控告警
## 回滚决策树
```
问题发现
├── 服务完全不可用?
│ └── YES → 立即回滚(紧急)
├── 核心功能异常?
│ └── YES → 评估影响范围 → 回滚或热修复
├── 非核心功能异常?
│ └── 评估修复时间
│ ├── < 30 分钟 → 热修复
│ └── > 30 分钟 → 回滚
└── 性能下降?
├── 严重(>5x → 回滚
└── 轻微(<2x → 监控 + 排期修复
```
## 回滚类型
### 1. Docker 镜像回滚(最常用)
```bash
# 查看历史镜像
docker images | grep ai-proj
# 回滚到上一版本
cd deploy
# 修改 docker-compose.prod.yml 中的镜像 tag
docker compose -f docker-compose.prod.yml up -d
# 验证
curl -s http://localhost:8080/health | jq .
```
### 2. 数据库回滚
```bash
# 执行 down migration
cd backend
migrate -path migrations -database "$DB_URL" down 1
# 验证表结构
psql -U user -d db -c "\d affected_table"
```
**注意**:数据库回滚可能导致数据丢失,必须先评估影响。
### 3. 配置回滚
```bash
# 恢复旧配置
git checkout HEAD~1 -- deploy/config/
docker compose -f docker-compose.prod.yml restart
```
## 回滚检查清单
- [ ] 确认问题现象和影响范围
- [ ] 通知相关人员(用户需知道在维护中)
- [ ] 执行回滚操作
- [ ] 验证服务恢复正常
- [ ] 验证数据完整性
- [ ] 记录回滚原因和过程
- [ ] 创建修复任务
## 回滚记录模板
```markdown
## 回滚记录
**时间**: YYYY-MM-DD HH:mm
**触发原因**: [问题描述]
**影响范围**: [受影响的功能/用户]
**回滚类型**: Docker 镜像 / 数据库 / 配置
**回滚操作**: [具体步骤]
**恢复确认**: [验证结果]
**根因分析**: [问题根因]
**修复计划**: [后续修复方案]
```
## 预防措施
- 部署前确保 Migration 有 down.sql
- 部署前确保 Docker 保留上一版本镜像
- 大变更使用灰度发布
- 监控关键指标错误率、延迟、CPU/内存)

View File

@@ -0,0 +1 @@
{"name":"dev-android-plugin","description":"Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。按需加载。","version":"1.0.0","author":{"name":"qiudl"}}

View File

@@ -0,0 +1,54 @@
---
name: dev-android
description: Android 开发插件。Kotlin + Jetpack Compose + Hilt 依赖注入。当涉及 Android 开发任务时按需加载。
---
# Android 开发插件 (dev-android)
## 架构MVVM + Hilt
```
android-app/app/src/main/
├── java/com/project/
│ ├── ui/ # Compose 屏幕 + 组件
│ ├── data/ # API + Repository + 本地存储
│ ├── domain/ # 业务逻辑
│ └── di/ # Hilt 依赖注入
└── res/ # 资源文件
```
## 代码规范
```kotlin
@HiltViewModel
class TaskViewModel @Inject constructor(
private val taskRepository: TaskRepository
) : ViewModel() {
private val _tasks = MutableStateFlow<List<Task>>(emptyList())
val tasks: StateFlow<List<Task>> = _tasks.asStateFlow()
fun fetchTasks() {
viewModelScope.launch {
taskRepository.getTasks()
.collect { _tasks.value = it }
}
}
}
@Composable
fun TaskListScreen(viewModel: TaskViewModel = hiltViewModel()) {
val tasks by viewModel.tasks.collectAsState()
LazyColumn {
items(tasks) { task -> TaskItem(task = task) }
}
}
```
## 构建
```bash
./gradlew assembleDebug # Debug 构建
./gradlew assembleRelease # Release 构建
./gradlew test # 测试
```

View File

@@ -0,0 +1,8 @@
{
"name": "dev-cicd-plugin",
"description": "Plugin for dev-cicd",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,599 @@
---
name: dev-cicd
description: CI/CD 流水线设计、优化与排查。适配 Gitea Actions + Go/Swift/Next.js/Docker 栈。当用户提到 CI、CD、流水线、pipeline、workflow、构建失败、runner 相关任务时自动激活。
---
# CI/CD 流水线技能 (dev-cicd)
## 概述
管理 Gitea Actions CI/CD 流水线的设计、优化和故障排查。适配技术栈:
- **Git**: Gitea (self-hosted, GitHub Actions YAML 兼容)
- **Backend**: Go (Gin + GORM)
- **iOS**: Swift 6 + SwiftUI + TCA
- **Web**: Next.js (React)
- **Container**: Docker + Docker Compose
- **Registry**: Aliyun ACR
- **Runners**: self-hosted (Linux) + macos-arm64 (iOS)
---
## 命令参考
| 命令 | 说明 |
|------|------|
| `/cicd analyze` | 分析当前 workflow 找优化点 |
| `/cicd troubleshoot` | 诊断流水线失败原因 |
| `/cicd template [go\|ios\|web\|docker]` | 生成 workflow 模板 |
| `/cicd status` | 查看最近 workflow 运行状态 |
---
## 1. Pipeline 设计
### 1.1 Monorepo 路径过滤
仓库包含多个子项目,用 `paths` 只触发相关构建:
```yaml
# .gitea/workflows/ci-cd.yml — Go + Web + Docker
on:
push:
branches: [develop, main]
paths:
- 'gateway/**'
- 'web/**'
- 'docker/**'
- 'scripts/**'
# .gitea/workflows/ios-testflight.yml — iOS 独立
on:
push:
branches: [develop, main]
paths:
- 'ios/**'
```
### 1.2 Pipeline 结构原则
```
快速反馈优先:
1. 静态检查 (lint/vet) — 秒级
2. 单元测试 (test) — 1-5 分钟
3. 构建 (build) — 2-10 分钟
4. 集成测试 (可选) — 5-15 分钟
5. 发布 (deploy) — 5-15 分钟
```
### 1.3 Go 后端模板
```yaml
jobs:
ci:
runs-on: self-hosted
steps:
- name: Checkout
run: |
cd ${{ github.workspace }}
if [ -d .git ]; then
git fetch --depth 1 origin ${{ github.ref_name }}
git reset --hard origin/${{ github.ref_name }}
else
git clone --depth 1 --branch ${{ github.ref_name }} \
http://xiaoqu:${{ secrets.REPO_TOKEN }}@localhost:3000/<org>/<repo>.git .
fi
- name: Go Vet
run: cd gateway && go vet ./...
- name: Go Test
run: cd gateway && go test ./... -count=1 -timeout 120s
- name: Go Build
run: cd gateway && go build ./cmd/gateway/
```
### 1.4 iOS 模板
```yaml
jobs:
ios:
runs-on: macos-arm64
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps:
- name: Checkout
run: git clone --depth 1 --branch ${{ github.ref_name }} <repo-url> .
- name: xcodegen
run: /opt/homebrew/bin/xcodegen generate
working-directory: ios
- name: Test
run: |
set -o pipefail
swift test 2>&1 | tee /tmp/test.log | tail -20
working-directory: ios
- name: Deploy TestFlight
env:
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
ASC_KEY_ID: ${{ secrets.ASC_KEY_ID }}
ASC_ISSUER_ID: ${{ secrets.ASC_ISSUER_ID }}
run: ./scripts/ios-testflight.sh
```
### 1.5 Web (Next.js) 模板
```yaml
- name: Web Install
run: cd web && npm ci --legacy-peer-deps
- name: Web Build
run: cd web && npm run build
- name: Docker Build Web
run: |
docker build -t $REGISTRY/$WEB_IMAGE:${{ github.sha }} \
-t $REGISTRY/$WEB_IMAGE:latest ./web
```
### 1.6 单 Job vs 多 Job
| 场景 | 选择 | 原因 |
|------|------|------|
| Runner capacity=1 | 单 Job | 多 Job 串行 + 多次 checkout = 更慢 |
| 多 Runner 可用 | 多 Job + needs | 并行加速 |
| 不同 OS (Linux+macOS) | 分 Workflow | 不同 runner label |
**当前推荐**Linux runner 单 JobGo+Web+DockermacOS runner 单 JobiOS
---
## 2. 优化
### 2.1 浅克隆
```yaml
# 首次 clone
git clone --depth 1 --branch ${{ github.ref_name }} <url> .
# 增量 fetch
git fetch --depth 1 origin ${{ github.ref_name }}
git reset --hard origin/${{ github.ref_name }}
```
**效果**仓库含大量二进制文件时clone 时间从 30s+ 降到 3-5s。
**注意**:需要 push 时先 `git fetch --unshallow`
### 2.2 依赖缓存
Gitea Actions 不支持 `actions/cache`,但 self-hosted runner 可利用本地磁盘:
```yaml
# Go modules — runner 上全局缓存
env:
GOMODCACHE: /opt/runner-cache/go/mod
GOCACHE: /opt/runner-cache/go/build
# npm — 利用 node_modules 持久化
# self-hosted runner 的 workspace 在两次运行间保留
- run: |
if [ -f web/node_modules/.cache-hash ] && \
[ "$(cat web/node_modules/.cache-hash)" = "$(md5sum web/package-lock.json | cut -d' ' -f1)" ]; then
echo "npm cache hit, skip install"
else
cd web && npm ci --legacy-peer-deps
md5sum package-lock.json | cut -d' ' -f1 > node_modules/.cache-hash
fi
# SPM — Xcode 自动缓存到 DerivedDataself-hosted runner 保留
```
### 2.3 并发取消
避免同一分支多次 push 排队等待:
```yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
```
### 2.4 条件跳过
```yaml
# 跳过 CI Bot 的自动提交
if: "!contains(github.event.head_commit.message, '[skip ci]')"
# 只在 develop 分支部署
if: github.ref == 'refs/heads/develop'
```
### 2.5 构建产物复用
```yaml
# Build once, use in deploy
- name: Build
run: go build -o /tmp/gateway ./cmd/gateway/
- name: Docker Build
run: |
# 用已编译的二进制,不在 Docker 内重新编译
cp /tmp/gateway docker/
docker build -f docker/gateway.prebuilt.Dockerfile -t $IMAGE .
```
### 2.6 Docker Context 瘦身
**问题**`docker build` 会将整个 context 目录发送到 daemon。缺少 `.dockerignore` 时,`node_modules`(数百 MB`.next/``.git/` 等全部传入,导致 `transferring context: 768MB` 耗时 30s+。
**诊断**
```bash
# 检查 context 大小(模拟 docker build 发送量)
du -sh --exclude=.git <project-dir>
# 检查是否有 .dockerignore
cat <project-dir>/.dockerignore 2>/dev/null || echo "缺少 .dockerignore!"
```
**`/cicd analyze` 必查项**:对每个有 Dockerfile 的目录检查 `.dockerignore` 是否存在。缺失则告警。
**标准 .dockerignore 模板**
```
# Node.js
node_modules
.next
.turbo
coverage
# Common
.git
.gitignore
.env*
*.md
.vscode
.idea
```
**效果**Web 项目 context 从 768MB → ~10MBDocker build 加速 10x。
**经验教训**`.gitignore` 不等于 `.dockerignore`。Git 忽略的文件可能在 runner workspace 中存在(如 self-hosted runner 保留的 `node_modules` 缓存docker build 会把它们全部打包传入。每个有 Dockerfile 的子目录**必须有 `.dockerignore`**。
---
## 3. 故障排查
### 3.1 决策树
```
Pipeline 失败
├── Workflow 没触发
│ ├── 检查 paths 过滤 → 改动不在匹配路径下
│ ├── 检查 branch 过滤 → 分支名不匹配
│ ├── 检查 [skip ci] → commit message 含跳过标记
│ └── Runner 离线 → Gitea Admin > Runners 检查状态
├── Checkout 失败
│ ├── "Authentication failed" → REPO_TOKEN secret 过期/无效
│ ├── "Connection refused :3000" → Gitea 服务未运行
│ └── Checkout 很慢 → 加 --depth 1 浅克隆
├── Go 构建失败
│ ├── "module not found" → GOPROXY 设置 / go mod tidy
│ ├── "cannot find package" → go.sum 不完整
│ └── "go: version mismatch" → runner 上 Go 版本与 go.mod 不匹配
├── iOS 构建失败
│ ├── "Macro must be enabled" → 加 -skipMacroValidation
│ ├── "cannot find type" → xcodegen generate 未运行
│ ├── "errSecInternalComponent" → unlock-keychain + set-key-partition-list
│ ├── "No signing certificate" → Xcode > Accounts 登录下载证书
│ ├── "Redundant Binary Upload" → 递增 CURRENT_PROJECT_VERSION
│ └── "Missing required icon" → Assets.xcassets 缺 1024x1024 icon
├── Docker 构建失败/慢
│ ├── "Cannot connect to daemon" → Docker Desktop 未启动
│ ├── "unauthorized" / "denied" → docker login 凭据过期 或 ACR namespace 缺失
│ ├── "no space left" → docker system prune
│ ├── "transferring context: XXX MB" 很慢 → 缺少 .dockerignorenode_modules 被传入)
│ ├── build 成功但 push denied → 镜像路径缺 namespaceregistry/namespace/image
│ ├── docker compose pull 超时 → 不带参数会拉 Docker Hub 上的 postgres/redis只拉业务镜像
│ └── docker compose up -d 也会 pull → 加 `--no-deps gateway web` 只重启业务容器
└── 部署失败
├── "Connection refused" (SSH) → 目标服务器 SSH 端口/密钥
├── "health check failed" → 应用启动慢,增加重试等待
├── "port already in use" → docker compose down 先停旧容器
├── "no such service: xxx" → 服务器 compose 与 CI 配置不一致
├── health check 失败但容器在跑 → curl URL 的端口与实际服务端口不匹配
├── --no-deps 跳过了 nginx → health check 走 port 80 但 nginx 未启动
├── gateway 无端口映射 → prod compose 不暴露端口,用 docker exec 检查
└── nginx crash "upstream not allowed" → nginx.conf mount 到 /etc/nginx/nginx.conf 覆盖主配置,改 /etc/nginx/conf.d/default.conf
```
### 3.2 常见错误速查
| 错误 | 原因 | 修复 |
|------|------|------|
| `errSecInternalComponent` | SSH 会话无法访问 Keychain | `security unlock-keychain` + `set-key-partition-list` |
| `Macro "X" must be enabled` | Swift Macros 安全限制 | `-skipMacroValidation` |
| `cannot find type 'Foo'` | xcodeproj 未包含新文件 | `xcodegen generate` |
| `Redundant Binary Upload` | build number 重复 | 递增 `CURRENT_PROJECT_VERSION` |
| `Cloud signing permission error` | API Key 权限不足或 Issuer ID 错误 | 用手动签名 + 本地 profile |
| `HTTP 401 Unauthorized` (ASC API) | JWT 缺少 `kid` header | `headers={"kid": KEY_ID}` |
| `No profiles for bundle id` | 无 distribution profile | 在 Apple Developer 创建并安装 |
| `transferring context: 768MB` | 缺 .dockerignore | 创建 .dockerignore 排除 node_modules/.next/.git |
| `denied: requested access` (push) | ACR 镜像路径缺 namespace | registry/**namespace**/image |
| `docker compose pull` 超时 | 拉了 Docker Hub 的 postgres/redis | `docker compose pull gateway web` 只拉业务镜像 |
| `docker compose up -d` 也超时 | up 隐含 pull 所有 service | `docker compose up -d --no-deps gateway web` |
| health check 失败但容器在跑 | curl URL 端口 ≠ 服务端口 | 检查 nginx(80) vs gateway(8080),直接 `curl :8080/health` |
| `--no-deps` 后 nginx 没启动 | nginx 被 no-deps 跳过 | 显式加 `--no-deps gateway web nginx` |
| `no such service: xxx` | 服务器 compose 缺 service | SSH 检查实际 compose 文件 |
| gateway healthy 但 curl 不通 | prod compose 无端口映射 | `docker exec <container> wget -q -O- localhost:8080/health` |
| nginx `upstream not allowed` | nginx.conf mount 到 /etc/nginx/nginx.conf | 改 mount 到 `/etc/nginx/conf.d/default.conf` |
| `missing icon file 120x120` | 无 App Icon asset | 创建 Assets.xcassets + AppIcon |
| `UIInterfaceOrientation` iPad | 缺 iPad 方向声明 | 四方向 + `UIRequiresFullScreen` |
### 3.3 调试技巧
```bash
# 查看 Gitea runner 状态
curl -s -H "Authorization: token <TOKEN>" \
http://<gitea>/api/v1/repos/<org>/<repo>/actions/runners
# 查看最近 workflow 运行
curl -s -H "Authorization: token <TOKEN>" \
http://<gitea>/api/v1/repos/<org>/<repo>/actions/runs?limit=5
# 本地模拟 CI 环境
# Go
docker run -v $(pwd):/app -w /app golang:1.25 go build ./cmd/gateway/
# iOS — 只能在 macOS 上
ssh bjwework "cd ~/workspace/xiaoqu-ai/ios && swift test"
```
---
## 4. 安全
### 4.1 Secrets 管理
```bash
# 通过 Gitea API 配置 secrets不要手动编辑 workflow 文件)
curl -X PUT -H "Authorization: token <ADMIN_TOKEN>" \
-H "Content-Type: application/json" \
"http://<gitea>/api/v1/repos/<org>/<repo>/actions/secrets/<NAME>" \
-d '{"data": "<VALUE>"}'
```
**必需 Secrets 清单**
| Secret | 用途 | 轮换周期 |
|--------|------|---------|
| `REPO_TOKEN` | Git clone 认证 | 按需 |
| `ACR_USERNAME` / `ACR_PASSWORD` | Docker 镜像推送 | 90 天 |
| `SSH_PRIVATE_KEY` | 服务器部署 | 按需 |
| `KEYCHAIN_PASSWORD` | macOS 签名解锁 | 改密码时 |
| `ASC_KEY_ID` / `ASC_ISSUER_ID` | App Store Connect | 按需 |
| `FEISHU_WEBHOOK` | 通知 | 不过期 |
### 4.2 防泄漏检查清单
- [ ] `.gitignore` 包含 `.env``*.p8``*.pem``*.mobileprovision`
- [ ] Workflow 中无硬编码密码/token全走 `${{ secrets.* }}`
- [ ] 脚本用 `${VAR:?error}` 强制要求环境变量(不用默认值暴露凭据)
- [ ] Docker 镜像不包含 `.env` 文件Dockerfile 有 `.dockerignore`
- [ ] Git remote URL 不含 token用 secrets 注入)
### 4.3 提交前检查
```bash
# 扫描即将提交的文件是否含密钥
git diff --cached --name-only | xargs grep -lE \
'(PRIVATE KEY|password|secret|token|apikey)' 2>/dev/null
```
---
## 5. 监控
### 5.1 查看 Pipeline 状态
```bash
# 最近运行
curl -s -H "Authorization: token <TOKEN>" \
"http://<gitea>/api/v1/repos/<org>/<repo>/actions/runs?limit=5" | \
python3 -c "
import json, sys
for r in json.load(sys.stdin).get('workflow_runs', []):
print(f\"{r['id']} | {r['display_title'][:40]} | {r['status']} | {r['conclusion']}\")
"
```
### 5.2 飞书通知模板
```yaml
# 成功/失败通知(在 workflow 最后一步 if: always()
- name: Notify
if: always()
run: |
STATUS="${{ job.status }}"
EMOJI=$([ "$STATUS" = "success" ] && echo "✅" || echo "❌")
COLOR=$([ "$STATUS" = "success" ] && echo "green" || echo "red")
cat > /tmp/notify.json << EOF
{
"msg_type": "interactive",
"card": {
"header": {
"title": {"tag": "plain_text", "content": "$EMOJI <App> $STATUS"},
"template": "$COLOR"
},
"elements": [{
"tag": "div",
"text": {"tag": "lark_md", "content": "**分支**: ${{ github.ref_name }}\n**提交**: ${{ github.sha }}\n**触发**: ${{ github.event.head_commit.message }}"}
}]
}
}
EOF
curl -s -X POST "${{ secrets.FEISHU_WEBHOOK }}" \
-H "Content-Type: application/json" -d @/tmp/notify.json || true
```
### 5.3 构建时间追踪
在 workflow 首尾加时间戳:
```yaml
steps:
- name: Start Timer
run: echo "BUILD_START=$(date +%s)" >> $GITHUB_ENV
# ... 构建步骤 ...
- name: Report Duration
if: always()
run: |
DURATION=$(( $(date +%s) - $BUILD_START ))
echo "Build duration: ${DURATION}s"
```
---
## 6. Runner 管理
### 6.1 Runner 类型
| Runner | 标签 | 用途 | 位置 |
|--------|------|------|------|
| xiaoqu-runner | `self-hosted` | Go + Web + Docker | 阿里云 39.104.65.241 |
| bjwework-macos | `macos-arm64` | iOS + Swift | Tailscale 100.69.230.116 |
### 6.2 新增 Runner
```bash
# 1. 获取注册 token
curl -s -H "Authorization: token <ADMIN_TOKEN>" \
"http://<gitea>/api/v1/repos/<org>/<repo>/actions/runners/registration-token"
# 2. 注册
./act_runner register --no-interactive \
--instance http://<gitea> \
--token <TOKEN> \
--name <NAME> \
--labels <LABEL>:host
# 3. 启动macOS 用 launchd
launchctl load ~/Library/LaunchAgents/com.gitea.act-runner.plist
```
### 6.3 Runner 健康检查
```bash
# 检查 runner 进程
ssh bjwework "launchctl list | grep act-runner"
# 检查 runner 日志
ssh bjwework "tail -20 ~/act_runner/runner.log"
# 检查 Gitea 上的 runner 状态
curl -s -H "Authorization: token <TOKEN>" \
"http://<gitea>/api/v1/repos/<org>/<repo>/actions/runners" | \
python3 -c "import json,sys; [print(f\"{r['name']} | {r['status']}\") for r in json.load(sys.stdin)]"
```
---
## 7. Workflow 模板生成
### `/cicd analyze` 检查清单
执行时自动扫描以下项目:
1. **Workflow YAML** — 语法检查、路径过滤、并发取消、[skip ci]
2. **Docker context** — 每个有 Dockerfile 的目录是否有 `.dockerignore`**必查**
3. **Secrets** — workflow 中是否有硬编码凭据、路径
4. **缓存** — 是否利用了依赖缓存npm/Go/SPM
5. **浅克隆** — checkout 是否用了 `--depth 1`
6. **镜像命名** — ACR/registry 路径是否包含 namespace
```bash
# 快速扫描命令
echo "=== .dockerignore 检查 ==="
find . -name Dockerfile -exec sh -c 'DIR=$(dirname "{}"); [ -f "$DIR/.dockerignore" ] && echo "✅ $DIR" || echo "❌ $DIR 缺少 .dockerignore"' \;
echo "=== 硬编码凭据检查 ==="
grep -rn 'password\|secret\|token' .gitea/workflows/ | grep -v 'secrets\.' | grep -v '#'
```
### `/cicd template go`
生成 Go 后端 CI workflow含 vet → test → build → docker → deploy。
### `/cicd template ios`
生成 iOS TestFlight workflow含 xcodegen → test → archive → upload → notify。
### `/cicd template web`
生成 Next.js CI workflow含 install → build → docker → deploy。
### `/cicd template docker`
生成 Docker multi-service build+push workflow含 ACR 登录 → 多镜像构建 → SSH 部署。
---
## 8. CD 部署前验证清单
**每次修改 deploy 步骤前必须逐项确认:**
```
1. 服务器 compose 有哪些 service
→ ssh <server> "docker compose -f <file> config --services"
2. CI deploy 启动了哪些 service
→ grep "up -d" .gitea/workflows/ci-cd.yml
3. health check URL 指向哪个端口?
→ grep "curl.*health" .gitea/workflows/ci-cd.yml
4. 该端口由哪个 service 服务?
→ port 80 = nginx, port 8080 = gateway, port 3001 = web
5. 该 service 是否在 deploy 启动列表中?
→ 如果 health check 走 nginx:80deploy 必须包含 nginx
6. 基础服务postgres/redis是否已运行
→ docker compose ps 检查,不要在 CI 中重启它们
7. Docker Hub 可达吗?
→ 国内服务器必须配镜像源,或只拉 ACR 镜像
```
**部署命令标准模板:**
```bash
# 只拉业务镜像(不触碰 Docker Hub
docker compose -f docker-compose.prod.yml pull gateway web
# 只重启业务容器 + nginx不动 postgres/redis
docker compose -f docker-compose.prod.yml up -d --no-deps gateway web nginx
# 直接检查 gateway 端口(不依赖 nginx
sleep 10
curl -sf http://localhost:8080/health
```
---
## 9. 与其他技能的关系
| 技能 | 协作点 |
|------|--------|
| `dev-deploy` | `/deploy ios` 执行 TestFlight 部署,`/deploy docker` 执行容器部署 |
| `dev-coding` | 开发完成后触发 CI |
| `req` | `/req deploy` 项目级批量部署 |
| `pull-request` | PR 触发 CI 检查 |
| `req-test-gate` | CI 中的测试门禁 |

View File

@@ -1,7 +1,7 @@
{
"name": "dev-coding-plugin",
"description": "Plugin for dev-coding",
"version": "1.0.0",
"description": "软件编码开发技能。Go 后端 + Vue/React 前端编码实现,集成 ai-proj 任务管理。",
"version": "2.0.0",
"author": {
"name": "qiudl"
}

View File

@@ -1,43 +1,24 @@
---
name: dev-coding
description: 软件编码开发技能。用于代码编写、功能实现、代码审查、重构优化。集成 ai-proj CLI 进行任务管理和进度跟踪。支持 GoVueReact、iOS、Android、小程序等全栈开发。
description: 软件编码开发技能。用于代码编写、功能实现、重构优化。集成 ai-proj CLI 进行任务管理和进度跟踪。核心支持 Go 后端 + Vue/React 前端开发。
---
# 软件编码开发 Skill (dev-coding)
## ⚠️ REQ 任务自动工作流
**当收到 REQ 任务(包含 REQ-YYYYMMDD-XXXX需要开发时必须严格按以下顺序执行**
1. **读取 ticket** — 从 ai-proj 获取需求详情和关联文档
```
mcp__ai-proj-dev__get_detailed_task_info (通过 REQ 号查找)
mcp__ai-proj-dev__get_task_document (如果有 PRD 文档)
```
2. **进入 Plan Mode** — 调用 `EnterPlanMode` 工具
- 分析需求,探索代码库,设计实现方案
- 输出实现计划(涉及的文件、改动范围、测试策略)
- 等待用户审批后再开始编码
3. **执行计划** — 用户批准后按计划编码 + 写测试
**禁止跳过 plan mode 直接编码。**
---
## 概述
本技能用于软件编码开发工作,支持多种项目类型
本技能用于软件编码实现,核心覆盖
- Go 后端 (Gin + GORM)
- Vue 3 / React 前端
- iOS (Swift/SwiftUI)
- Android (Kotlin/Jetpack Compose)
- PDA 应用
- MCP 桥接服务
- 微服务架构
核心集成 **ai-proj CLI** 进行任务管理。
集成 **ai-proj CLI** 进行任务管理。
**不包含**(由其他技能/插件负责):
- 开发设计API 契约、任务拆分)→ `req-design`
- 代码评审 → `dev-review`批次2
- iOS 开发 → `dev-ios`(插件)
- Android 开发 → `dev-android`(插件)
- MCP 开发 → `dev-mcp`(插件)
---
@@ -84,11 +65,11 @@ ai-proj task append-doc --id <taskId> --content "实现说明"
### 当前项目生态
| 项目 | 类型 | 后端 | 前端 | 移动端 |
|------|------|------|------|--------|
| TWMS | 仓储物流 | Go+Gin+MySQL | Vue 3 | - |
| AI-Proj | 项目管理 | Go+Gin+PostgreSQL | React 18 | iOS+Android |
| DICIAI | 进销存SaaS | Go+Gin+MySQL | Vue 3 | Android PDA |
| 项目 | 类型 | 后端 | 前端 |
|------|------|------|------|
| TWMS | 仓储物流 | Go+Gin+MySQL | Vue 3 |
| AI-Proj | 项目管理 | Go+Gin+PostgreSQL | React 18 |
| DICIAI | 进销存SaaS | Go+Gin+MySQL | Vue 3 |
---
@@ -349,309 +330,6 @@ npm run test:e2e
---
## iOS 开发 (Swift/SwiftUI)
### 项目结构
```
AI-Proj-iOS/
├── Core/ # 核心服务
│ ├── Network/ # 网络层
│ ├── Storage/ # 本地存储
│ └── Auth/ # 认证
├── Features/ # 功能模块
│ ├── Dashboard/
│ ├── Tasks/
│ └── Settings/
├── Models/ # 数据模型
└── UI/ # UI 组件
```
### 代码规范
```swift
// MVVM 架构
class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
@Published var isLoading = false
private let taskService: TaskServiceProtocol
init(taskService: TaskServiceProtocol = TaskService()) {
self.taskService = taskService
}
func fetchTasks() async {
isLoading = true
defer { isLoading = false }
do {
tasks = try await taskService.getTasks()
} catch {
// 错误处理
}
}
}
// SwiftUI 视图
struct TaskListView: View {
@StateObject private var viewModel = TaskViewModel()
var body: some View {
List(viewModel.tasks) { task in
TaskRow(task: task)
}
.task {
await viewModel.fetchTasks()
}
}
}
```
### 构建命令
```bash
# Xcode 构建
xcodebuild -scheme AI-Proj-iOS -configuration Debug
# 测试
xcodebuild test -scheme AI-Proj-iOS
```
### 常见问题排查
#### SwiftLint 沙盒错误
**问题描述**
构建时出现错误:
```
Sandbox: swiftlint(xxxx) deny(1) file-read-data /path/to/.swiftlint.yml
```
**原因**
Xcode 15+ 默认启用 User Script Sandboxing限制脚本访问文件系统。
**解决方案**
方案 1 - 修改项目配置(推荐):
1. 打开 Xcode → 选择项目 → Build Settings
2. 搜索 "User Script Sandboxing"
3. 将 `ENABLE_USER_SCRIPT_SANDBOXING` 设置为 `NO`
方案 2 - 命令行构建时禁用:
```bash
xcodebuild -scheme AI-Proj-iOS -configuration Debug \
ENABLE_USER_SCRIPT_SANDBOXING=NO
```
方案 3 - 直接修改 project.pbxproj
```bash
sed -i '' 's/ENABLE_USER_SCRIPT_SANDBOXING = YES/ENABLE_USER_SCRIPT_SANDBOXING = NO/g' \
AI-Proj-iOS.xcodeproj/project.pbxproj
```
#### Personal Development Team 功能限制
**问题描述**
使用免费 Personal Team 签名时报错:
```
Cannot create iOS App Development provisioning profile...
Personal development teams do not support the Associated Domains,
Push Notifications and App Groups capabilities.
```
**原因**
Personal Team免费账户不支持以下 Entitlements
- Associated Domains (`com.apple.developer.associated-domains`)
- Push Notifications (`aps-environment`)
- App Groups (`com.apple.security.application-groups`)
**解决方案**
1. 从 Entitlements 文件中移除不支持的功能:
```xml
<!-- AI-Proj-iOS.entitlements -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- 仅保留 Personal Team 支持的功能 -->
<key>keychain-access-groups</key>
<array>
<string>$(AppIdentifierPrefix)com.yourcompany.app</string>
</array>
</dict>
</plist>
```
2. Personal Team 支持的功能:
- Keychain Access Groups ✓
- In-App Purchase ✓
- Game Center ✓
3. 需要付费 Apple Developer Program 的功能:
- Push Notifications ✗
- Associated Domains ✗
- App Groups ✗
- CloudKit ✗
- Sign in with Apple ✗
---
## Android 开发 (Kotlin)
### 项目结构
```
android-app/app/src/main/
├── java/com/project/
│ ├── ui/ # UI 层
│ │ ├── screens/ # Compose 屏幕
│ │ └── components/ # 可复用组件
│ ├── data/ # 数据层
│ │ ├── api/ # 网络接口
│ │ ├── repository/ # 仓库模式
│ │ └── local/ # 本地存储
│ ├── domain/ # 业务逻辑
│ └── di/ # 依赖注入
└── res/ # 资源文件
```
### 代码规范
```kotlin
// Hilt 依赖注入
@HiltViewModel
class TaskViewModel @Inject constructor(
private val taskRepository: TaskRepository
) : ViewModel() {
private val _tasks = MutableStateFlow<List<Task>>(emptyList())
val tasks: StateFlow<List<Task>> = _tasks.asStateFlow()
fun fetchTasks() {
viewModelScope.launch {
taskRepository.getTasks()
.collect { _tasks.value = it }
}
}
}
// Jetpack Compose
@Composable
fun TaskListScreen(
viewModel: TaskViewModel = hiltViewModel()
) {
val tasks by viewModel.tasks.collectAsState()
LazyColumn {
items(tasks) { task ->
TaskItem(task = task)
}
}
}
```
### 构建命令
```bash
# 构建 Debug
./gradlew assembleDebug
# 构建 Release
./gradlew assembleRelease
# 测试
./gradlew test
```
---
## PDA 应用开发
### 特点
- Android 原生开发
- 扫码枪集成
- 离线优先
- 简洁 UI
### 常见功能
```kotlin
// 扫码处理
class ScanReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val barcode = intent.getStringExtra("SCAN_BARCODE")
// 处理扫码结果
}
}
// 离线存储
@Entity(tableName = "inventory")
data class Inventory(
@PrimaryKey val id: Long,
val barcode: String,
val quantity: Int,
@ColumnInfo(name = "sync_status")
val syncStatus: SyncStatus = SyncStatus.PENDING
)
```
---
## MCP 桥接开发
### 项目结构
```
mcp-task-bridge/
├── index.ts # 入口
├── task-service.ts # 任务服务
├── document-service.ts # 文档服务
├── base-client.ts # HTTP 基类
├── types.ts # 类型定义
└── token-storage.ts # Token 管理
```
### 代码规范
```typescript
// 服务类模式
export class TaskService extends BaseClient {
async createTask(
title: string,
projectId: number = 1,
options: CreateTaskOptions = {}
): Promise<ApiResponse<Task>> {
try {
const response = await this.makeRequest<Task>(
'POST',
`/projects/${projectId}/tasks`,
{ title, project_id: projectId, ...options }
);
if (response.success) {
return {
success: true,
data: response.data,
message: `✅ 任务 "${title}" 创建成功`
};
}
return response;
} catch (error: any) {
return {
success: false,
error: `创建任务失败: ${error.message}`
};
}
}
}
```
---
## 通用开发规范
### API 响应格式
@@ -695,13 +373,6 @@ try {
} catch (error) {
message.error(error.message);
}
// Swift
do {
let result = try await service.fetch()
} catch {
// 处理错误
}
```
---
@@ -808,3 +479,66 @@ fi
4. **小步提交** - 频繁提交,每次做一件事
5. **测试覆盖** - 核心逻辑必须有测试
6. **文档同步** - 代码变更同步更新文档
## 相关技能
| 技能 | 用途 |
|------|------|
| `req-design` | 开发设计API 契约、任务拆分)— dev-coding 的输入 |
| `dev-test` | 测试与质量门禁 |
| `dev-review` | 代码评审(五视角扫描)|
| `dev-ios` | iOS 开发(插件,按需加载)|
| `dev-android` | Android 开发(插件,按需加载)|
| `dev-mcp` | MCP bridge 开发(插件,按需加载)|
---
## CLAUDE.md 架构检查机制REQ-20260416-0017 P0-5
**原则:本 skill 不硬编码任何项目的架构细节,从项目 CLAUDE.md 读取**
### 为什么
同一套 skill 要支持多个技术栈Go+Gin / React+AntD / Vue+Element / Python+FastAPI。如果把分层、命名、目录结构写死在 SKILL.md 里,跨项目就会冲突。
devflow-claude 的做法借鉴skill 只管**流程和模板**,项目架构由 CLAUDE.md 的 "Architecture" / "项目架构" 章节定义。
### 执行前检查
开始编码任务前skill 先检查项目根 `CLAUDE.md`
```bash
# 检查 CLAUDE.md 是否含架构关键词
if [ -f "CLAUDE.md" ]; then
if grep -qiE "(架构|分层|目录结构|tech stack|architecture|project structure)" CLAUDE.md; then
echo "✅ 检测到项目架构信息"
else
echo "⚠️ CLAUDE.md 缺少架构描述"
echo " dev-coding 需要架构信息来生成准确的文件路径和分层顺序"
echo ""
echo " 📋 建议操作:"
echo " - 查看预置架构片段: ai-proj-helper/skills-dev/dev-coding-plugin/templates/claude-md-snippets/"
echo " - 选择匹配技术栈的片段,补充到 CLAUDE.md 的 '## Architecture' 章节"
echo ""
echo " ⚠️ 继续执行,但生成的文件路径可能不够准确"
fi
else
echo "⚠️ 未找到项目 CLAUDE.md建议创建"
fi
```
### 架构片段模板库
位于 `skills-dev/dev-coding-plugin/templates/claude-md-snippets/`
| 文件 | 适用场景 |
|------|---------|
| `go-gin-gorm.md` | Go + Gin + GORM 后端ai-proj backend 风格) |
| `react-antd.md` | React + TypeScript + Ant Designai-proj frontend 风格) |
| `vue-element.md` | Vue 3 + Element Pluscoolbuy-paas 风格) |
| `mcp-typescript.md` | MCP bridge TypeScriptmcp-task-bridge 风格) |
| `generic.md` | 通用空白骨架 |
### 非阻断原则
架构信息缺失时**仅警告不阻止**。用户仍可继续,但会被告知"生成的建议可能不够准确"。

View File

@@ -0,0 +1,47 @@
<!-- 复制此片段到项目根 CLAUDE.md 的 "## Architecture" 章节,按实际情况填写 -->
## Architecture
### 技术栈
- **语言**: _TODO_
- **框架**: _TODO_
- **数据库**: _TODO_
- **缓存**: _TODO_
- **部署**: _TODO_
### 目录结构
```
project-root/
├── ???/ # _TODO: 说明_
├── ???/ # _TODO_
└── ???/
```
### 分层 / 模块规则
1. _TODO: 依赖方向_
2. _TODO: 允许/禁止的跨层调用_
### 命名规范
| 类型 | 约定 | 示例 |
|------|------|------|
| _TODO_ | _TODO_ | _TODO_ |
### 错误处理
_TODO_
### 日志
_TODO_
### 测试
_TODO_
### 其他关键约定
- _TODO_

View File

@@ -0,0 +1,56 @@
<!-- 复制此片段到项目根 CLAUDE.md 的 "## Architecture" 章节 -->
## Architecture
### 分层结构Go + Gin + GORM
```
backend/
├── routes/ # HTTP 路由定义(按模块拆分)
├── handlers/ # 请求解析 + 响应组装(薄层,不含业务)
├── services/ # 业务逻辑(事务、组合、校验)
├── models/ # GORM 数据模型
├── database/ # Repository 层SQL、查询
├── middleware/ # 认证、CORS、日志、限流
├── migrations/ # SQL 迁移文件
└── utils/ # 通用工具(密码、签名等)
```
### 分层规则(强制)
1. **请求流向**Route → Handler → Service → Database → Models
2. **Handler 禁止直接访问 database**:必须走 Service 层
3. **Service 禁止调用 Handler 或 Route**:单向依赖
4. **Model 仅定义结构 + GORM tag**:不含业务方法
### 命名规范
| 类型 | 约定 | 示例 |
|------|------|------|
| 文件名 | snake_case | `user_service.go` |
| 包名 | lowercase | `services`, `handlers` |
| 导出函数/类型 | PascalCase | `CreateUser`, `UserRepository` |
| 内部函数 | camelCase | `validatePassword` |
| 常量 | SCREAMING_SNAKE_CASE | `MAX_RETRY_COUNT` |
### 错误处理
- 使用 `errors.New()` 或自定义 error type
- Handler 层统一返回 `{"code": X, "msg": "...", "data": ...}`
- Service 层返回原始 error由 Handler 转换
### 日志
- 使用结构化 log`log.WithField("user_id", uid).Info("...")`
- 禁用 `fmt.Println` / `print`
### 测试
- 单元测试文件名:`xxx_test.go`
- 使用 `testify/assert`
- Mock 用 `testify/mock``gomock`
### 依赖检查
- **新 handler 禁止直接 `import database/`**:需走 Service 层
- `./scripts/check-architecture.sh check` 作为 CI 门禁

View File

@@ -0,0 +1,75 @@
<!-- 复制此片段到项目根 CLAUDE.md 的 "## Architecture" 章节 -->
## Architecture
### 目录结构MCP Bridge - TypeScript
```
mcp-task-bridge/
├── src/
│ ├── tools/ # MCP tool 定义(每个工具一个文件)
│ ├── resources/ # MCP resources若有
│ ├── prompts/ # MCP prompts若有
│ ├── client/ # 后端 REST API 客户端
│ ├── utils/ # 工具函数
│ └── index.ts # 入口
├── tests/
└── dist/ # 编译产物(不提交)
```
### 工具定义规范
每个 MCP tool 一个文件:
```typescript
// tools/create-task.ts
export const createTaskTool: Tool = {
name: 'create_task',
description: '...',
inputSchema: {
type: 'object',
properties: { ... },
required: [...]
}
};
export async function handleCreateTask(args) { ... }
```
### 后端 API 调用
- 所有 REST 请求通过 `src/client/api.ts` 统一封装
- 认证头由 client 自动附加(不在 tool 里处理)
- 错误统一转成 MCP error response
### 命名规范
| 类型 | 约定 | 示例 |
|------|------|------|
| MCP tool name | snake_case | `create_task`, `list_requirements` |
| 文件名 | kebab-case | `create-task.ts` |
| 函数名 | camelCase | `handleCreateTask` |
| Tool 变量 | camelCase + `Tool` | `createTaskTool` |
### 构建与部署
- `npm run build``dist/`
- **修改代码后必须重新 build**`pkill -f mcp-task-bridge/dist/index.js` 重启 MCP server
- 不能直接运行 TypeScript 源码
### 环境配置
- `dev` 环境:`ai-proj-dev` MCP server
- `prod` 环境:`ai-proj-prod` MCP server
- 禁止跨环境传数据dev 需求不能关联 prod 任务)
### 测试
- Jest + ts-jest
- 集成测试模拟真实 MCP 协议
### 常见错误
- **Rule 1**: MCP 端点必须 `/api/v1/mcp/` 前缀
- **Rule 2**: 修改后必须 rebuild + 重启
- **Rule 3**: 环境隔离dev / prod

View File

@@ -0,0 +1,78 @@
<!-- 复制此片段到项目根 CLAUDE.md 的 "## Architecture" 章节 -->
## Architecture
### 目录结构React + TypeScript + Ant Design
```
frontend/src/
├── pages/ # 页面级组件(路由对应)
├── components/ # 可复用 UI 组件
├── services/ # API 客户端Axios 封装)
├── hooks/ # 自定义 React Hooks
├── contexts/ # Context Providersauth, timer 等)
├── utils/ # 工具函数auth, validation, date 等)
├── types/ # TypeScript 类型定义
└── config/ # Feature flags, 性能配置
```
### 状态管理
| 状态类型 | 方案 |
|---------|------|
| 服务器状态 | React Query (TanStack Query) |
| 全局状态 | Context API |
| 本地状态 | useState / useReducer |
| 表单状态 | Ant Design Form |
**禁止**Redux / MobX本项目不使用
### 路由
- React Router v6
- 路由定义集中在 `src/routes/`
- 懒加载:`const Page = lazy(() => import(...))`
### API 调用
- 使用 `services/` 下的封装函数,不要在组件里直接 `axios.get`
- 响应类型必须有 TypeScript interface
- 错误统一由 axios 拦截器处理
### 样式
- Ant Design 组件 + CSS Module
- 禁止内联 `style={{ ... }}` 用于复杂样式
- 全局变量走 CSS Variables
### Modal 安全规则(重要)
`Modal.success/info/warning/error` 是非阻塞调用,后续 UI 操作必须放在 `onOk` 回调中:
```tsx
// WRONG
Modal.success({ title: '成功' });
setNextModalOpen(true); // 立即执行,两个 modal 冲突
// CORRECT
Modal.success({
title: '成功',
onOk: () => setNextModalOpen(true),
});
```
### 命名规范
| 类型 | 约定 | 示例 |
|------|------|------|
| 组件文件 | PascalCase | `UserProfile.tsx` |
| Hook 文件 | camelCase | `useAuth.ts` |
| 工具文件 | kebab-case | `date-utils.ts` |
| 组件名 | PascalCase | `UserProfile` |
| Hook 名 | `use` 前缀 | `useAuth` |
### 测试
- 单测Jest + React Testing Library
- E2EPlaywright
- 测试文件:`xxx.test.tsx` 与源文件同目录

View File

@@ -0,0 +1,67 @@
<!-- 复制此片段到项目根 CLAUDE.md 的 "## Architecture" 章节 -->
## Architecture
### 目录结构Vue 3 + TypeScript + Element Plus
```
src/
├── views/ # 页面级组件(路由对应)
├── components/ # 可复用组件
├── api/ # API 封装
├── stores/ # Pinia stores
├── composables/ # 组合式函数use* hooks
├── utils/ # 工具函数
├── types/ # TypeScript 类型定义
└── router/ # Vue Router 配置
```
### 状态管理
- **Pinia**(官方推荐)
- 每个业务模块一个 store`stores/user.ts``stores/order.ts`
- 禁止直接在组件里写持久状态
### 路由
- Vue Router 4
- 路由守卫统一在 `router/guards.ts`
- 懒加载:`component: () => import('@/views/...')`
### Composition API
- **强制使用 `<script setup>`**,禁止 Options API
- Props 用 `defineProps<T>()`Emits 用 `defineEmits<T>()`
### API 调用
- `api/` 下按模块划分:`api/user.ts``api/order.ts`
- 每个函数返回类型明确
- 错误由 axios 拦截器统一处理
### 命名规范
| 类型 | 约定 | 示例 |
|------|------|------|
| 组件文件 | PascalCase | `UserProfile.vue` |
| Composable | camelCase + use 前缀 | `useAuth.ts` |
| Store | camelCase | `useUserStore` |
| API 文件 | kebab-case | `user-api.ts` |
| 工具函数 | camelCase | `formatDate` |
### 样式
- SCSS + Element Plus 主题
- scoped style避免全局污染
- 全局变量走 SCSS 变量或 CSS Variables
### 国际化
- 使用 vue-i18n
- 消息文件:`src/locales/zh.json` / `en.json`
- 禁止硬编码文本:用 `t('path.to.key')`
### 测试
- 单测Vitest + Vue Test Utils
- E2EPlaywright / Cypress

View File

@@ -0,0 +1,8 @@
{
"name": "dev-commit-plugin",
"description": "智能 /commit 命令:分支保护 + 自动建功能分支 + Conventional Commits 生成",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,144 @@
---
name: dev-commit
description: 智能 git commit — 分支保护 + 自动建功能分支 + Conventional Commits 生成。当用户说"提交代码"、"commit"、"/commit"、"保存修改"时自动激活。
---
# dev-commit Skill — 智能提交
借鉴自 devflow-claude `/req:commit`。源自 REQ-20260416-0017 P0-6。
## 核心功能
**用户说"/commit" 或 "提交代码" 时执行:**
1. **分支合规检查**
2. **自动建功能分支**(若在保护分支)
3. **Conventional Commits 生成**
4. **自动关联 REQ-XXX**
## 流程详解
### 1. 分支合规检查(强制)
```bash
CURRENT_BRANCH=$(git symbolic-ref --short HEAD)
# 保护分支名单
PROTECTED_BRANCHES="main master develop production"
for b in $PROTECTED_BRANCHES; do
if [ "$CURRENT_BRANCH" = "$b" ]; then
IS_PROTECTED=1
break
fi
done
```
**铁律****绝对禁止**在 main / develop / master / production 分支上直接 commit。
### 2. 保护分支上有改动 → 自动建功能分支
```
检测到 main/develop 有未提交改动:
推荐方案:
1. 自动建分支 feat/xxx 并切换过去(推荐)
2. 取消本次 commit手动切分支
3. 临时 stash 后切分支
【默认选 1】
```
**分支命名自动推断:**
- 从对话上下文:如果刚在讨论 "REQ-20260416-0017" → `feat/REQ-20260416-0017-summary`
- 从文件变更:扫描 staged files 的路径 → 推断模块(如 `backend/services/user/``feat/user-xxx`
- 从 commit message 意图:如果意图是 fix → `fix/xxx`
**前缀规则:**
- `feat/` — 新功能
- `fix/` — bug 修复
- `chore/` — 杂项依赖升级、CI 调整等)
- `refactor/` — 重构
- `docs/` — 文档
### 3. Conventional Commits 生成
**格式:**
```
<type>(<scope>): <description> [(REQ-XXX)] [closes #N]
```
**type**
- feat - 新功能
- fix - 修复
- chore - 杂项
- refactor - 重构
- docs - 文档
- test - 测试
- perf - 性能
- style - 格式
**scope**
- 从修改的文件路径推断:`backend/services/user/``user`
- `frontend/src/pages/login/``login`
**示例:**
```
feat(mcp): 新增 set_requirement_reviewers 工具 (REQ-20260415-0023)
fix(frontend): 403 权限重载死循环
chore(cicd): 精简 CI/CD 流程,移除 Staging 环境 (REQ-20260415-0004) closes #242
```
### 4. REQ-XXX 自动关联
**查找顺序:**
1. 当前分支名:`feat/REQ-20260416-0017-xxx` → 提取 `REQ-20260416-0017`
2. 最近对话中提到的 REQ ID
3. MCP 查询当前用户的"进行中"需求(如只有一个,直接用)
**分支名含 `-iN` 时追加 `closes #N`**
```
feat/REQ-xxx-i42 + commit → commit message 自动加 "closes #42"
```
### 5. 提交确认
提交前展示预览:
```
即将执行:
分支: feat/mcp-set-reviewers
Files: backend/mcp/tools/set_reviewers.go, mcp-task-bridge/src/tools/set-reviewers.ts
Message:
feat(mcp): 新增 set_requirement_reviewers 工具 (REQ-20260415-0023)
确认提交?(y/n)
```
## 与 ai-proj 集成
- **查询当前需求**:通过 MCP `mcp__ai-proj__find_requirement``list_requirements` 找 user 进行中的
- **commit 后可选**:调用 `mcp__ai-proj__update_task` 更新关联任务进度
## 排除项
本 skill **不做**
- 推送远程(留给 `/pr``git push`
- 创建 PR留给 pull-request skill
- 代码评审(留给 dev-review skill
职责边界清晰,防止单命令膨胀。
## 风险控制
1. **保护分支改动不得 commit** — 强制拦截
2. **message 必须用 Conventional Commits** — 后续 changelog 依赖
3. **REQ-XXX 关联尽量自动推断** — 但推断不出不阻断
## 安装方式
本 skill 自动随 ai-proj-helper marketplace 加载。用户说"/commit" 即激活。
## 参考
- devflow-claude: `plugins/req/commands/commit.md`
- REQ-20260416-0017 P0-6

View File

@@ -0,0 +1,8 @@
{
"name": "dev-deploy-plugin",
"description": "Plugin for dev-deploy",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,776 @@
---
name: dev-deploy
description: 应用部署技能。支持 iOS TestFlight、Docker 容器等多平台部署。当用户提到部署、发布、TestFlight、上架、build、archive 相关任务时自动激活。
---
# 应用部署 Skill (dev-deploy)
## 概述
管理应用从构建到发布的完整部署流程,支持多平台:
- **iOS**: TestFlight 内测 / App Store 发布
- **Docker**: Staging / Production 容器部署
集成 ai-proj 任务系统进行部署记录和需求阶段推进。
---
## 命令参考
| 命令 | 说明 |
|------|------|
| `/deploy ios` | iOS TestFlight 部署 |
| `/deploy docker [staging\|prod]` | Docker 容器部署 |
| `/deploy status` | 查看部署状态 |
---
## iOS TestFlight 部署
### 前置条件
| 项目 | 要求 |
|------|------|
| 构建机器 | macOS + Xcode通过 SSH 访问) |
| 签名证书 | Apple Distribution 证书已安装在 Keychain |
| Provisioning Profile | App Store Distribution profile 已安装 |
| API Key | App Store Connect API Key (.p8) |
| sshpass | 本机安装用于非交互 SSH`brew install hudochenkov/sshpass/sshpass` |
| xcodegen | 构建机器安装用于从 project.yml 生成 xcodeproj |
### 完整部署流程
```
1. git push → 代码推送到远程仓库
2. SSH 连接构建机 → git pull 拉取最新代码
3. xcodebuild archive → 无签名构建 Archive
4. xcodebuild -exportArchive → Distribution 签名 + 上传 TestFlight
5. ASC API 补全 → 合规信息 + 测试说明 + build 关联版本
6. 验证 → 确认 TestFlight 状态为 IN_BETA_TESTING
```
### Step 1: SSH 连接构建机
```bash
# 使用 sshpass 进行非交互 SSH
sshpass -p '<password>' ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no <user>@<host> '<command>'
```
**关键经验**
- SSH 远程 codesign 需要先**解锁 Keychain**,否则报 `errSecInternalComponent`
- 还需要 `set-key-partition-list` 授权 codesign 访问密钥
```bash
# 必须在每次 SSH 会话开头执行
security unlock-keychain -p "<password>" ~/Library/Keychains/login.keychain-db
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "<password>" ~/Library/Keychains/login.keychain-db
```
### Step 2: 拉取代码
```bash
cd <repo-path> && git pull origin develop
```
### Step 3: Archive无签名
**关键经验**Archive 阶段**不要签名**。原因:
- xcodebuild CLI 签名参数会泄漏到 SPM 依赖的 targets导致 "does not support provisioning profiles" 错误
- 正确做法是 archive 时禁用签名,在 export 阶段单独签名
```bash
xcodebuild archive \
-project XiaoquCRM.xcodeproj \
-scheme XiaoquCRM \
-destination 'generic/platform=iOS' \
-configuration Release \
-archivePath ~/Desktop/XiaoquCRM.xcarchive \
-skipMacroValidation \
CODE_SIGNING_ALLOWED=NO \
CODE_SIGNING_REQUIRED=NO
```
**常见错误及解决**
| 错误 | 原因 | 解决 |
|------|------|------|
| `Macro "X" must be enabled` | Swift Macros 安全限制 | 加 `-skipMacroValidation` |
| `cannot find type 'AdminFeature'` | xcodeproj 未包含新文件 | 运行 `xcodegen generate` 重新生成 |
| SPM 依赖报签名错误 | 签名参数泄漏到依赖 | Archive 用 `CODE_SIGNING_ALLOWED=NO` |
### Step 4: Export + 上传 TestFlight
```bash
# ExportOptions.plist提前创建在构建机上
cat > /tmp/ExportOptions.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store-connect</string>
<key>destination</key>
<string>upload</string>
<key>teamID</key>
<string>{TEAM_ID}</string>
<key>signingStyle</key>
<string>manual</string>
<key>signingCertificate</key>
<string>Apple Distribution</string>
<key>provisioningProfiles</key>
<dict>
<key>{BUNDLE_ID}</key>
<string>{PROFILE_NAME}</string>
</dict>
<key>manageAppVersionAndBuildNumber</key>
<true/>
</dict>
</plist>
EOF
# Export + Upload
xcodebuild -exportArchive \
-archivePath ~/Desktop/XiaoquCRM.xcarchive \
-exportOptionsPlist /tmp/ExportOptions.plist \
-exportPath ~/Desktop/XiaoquCRM-export \
-authenticationKeyPath {API_KEY_PATH} \
-authenticationKeyID {KEY_ID} \
-authenticationKeyIssuerID {ISSUER_ID}
```
**关键经验**
| 问题 | 教训 |
|------|------|
| `errSecInternalComponent` | SSH 远程签名前必须 `unlock-keychain` + `set-key-partition-list` |
| `No signing certificate "iOS Distribution"` | 机器上没装 Distribution 证书,需在 Xcode > Accounts 登录 Apple ID 下载 |
| `Redundant Binary Upload` | build number 重复,需要在 project.yml 递增 `CURRENT_PROJECT_VERSION` |
| `Missing required icon file` | 需要 Assets.xcassets/AppIcon.appiconset 含 1024x1024 PNG |
| `UIInterfaceOrientation` iPad 错误 | 必须声明 iPad 四方向支持,或设置 `UIRequiresFullScreen=true` |
| `Cloud signing permission error` | API Key 权限不够或 Issuer ID 错误;改用手动签名 + 本地 profile |
### Step 5: ASC API 补全 TestFlight 信息
上传成功后,需要通过 App Store Connect API 补全三项信息,否则测试者收不到通知或无法安装:
#### 5.1 生成 JWT Token
```python
import jwt, time
key = open("AuthKey_XXXXXX.p8").read()
token = jwt.encode(
{"iss": "{ISSUER_ID}", "iat": int(time.time()),
"exp": int(time.time()) + 1200, "aud": "appstoreconnect-v1"},
key, algorithm="ES256",
headers={"kid": "{KEY_ID}"} # ← 必须包含 kid
)
```
**关键经验**JWT 必须包含 `headers={"kid": KEY_ID}`,否则 401 认证失败。还需要安装 `cryptography` 库支持 ES256。
#### 5.2 设置出口合规
```
PATCH /v1/builds/{build_id}
{"data": {"type": "builds", "id": "{build_id}",
"attributes": {"usesNonExemptEncryption": false}}}
```
不设置此项build 会卡在 "Missing Compliance" 状态,内部测试者无法安装。
#### 5.3 填写测试说明 (whatsNew)
```
# 先获取 localization ID
GET /v1/builds/{build_id}/betaBuildLocalizations
# 更新 whatsNew
PATCH /v1/betaBuildLocalizations/{loc_id}
{"data": {"type": "betaBuildLocalizations", "id": "{loc_id}",
"attributes": {"whatsNew": "更新内容..."}}}
```
#### 5.4 关联 Build 到 App Store 版本
**关键经验**App Store Connect 页面的 App Icon 来自关联的 build。如果没有把 build 关联到 App Store 版本,图标显示为空。
```
# 关联 build 到版本
PATCH /v1/appStoreVersions/{version_id}/relationships/build
{"data": {"type": "builds", "id": "{build_id}"}}
```
### Step 6: 验证部署状态
```python
# 检查 build 状态
GET /v1/builds/{build_id}?include=buildBetaDetail
# 期望结果:
# processingState: VALID
# internalBuildState: IN_BETA_TESTING
# usesNonExemptEncryption: false
```
### 一键部署脚本模板
将以上步骤整合为单次 SSH 调用:
```bash
sshpass -p '<password>' ssh -o PreferredAuthentications=password \
-o PubkeyAuthentication=no <user>@<host> '
# 0. Keychain
security unlock-keychain -p "<password>" ~/Library/Keychains/login.keychain-db
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "<password>" ~/Library/Keychains/login.keychain-db 2>/dev/null
# 1. Pull
cd <repo> && git pull origin develop
# 2. Archive
cd ios && rm -rf ~/Desktop/App.xcarchive ~/Desktop/App-export
xcodebuild archive -project App.xcodeproj -scheme App \
-destination "generic/platform=iOS" -configuration Release \
-archivePath ~/Desktop/App.xcarchive \
-skipMacroValidation CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO \
2>&1 | tail -1
# 3. Export + Upload
xcodebuild -exportArchive \
-archivePath ~/Desktop/App.xcarchive \
-exportOptionsPlist /tmp/ExportOptions.plist \
-exportPath ~/Desktop/App-export \
-authenticationKeyPath <key_path> \
-authenticationKeyID <key_id> \
-authenticationKeyIssuerID <issuer_id> \
2>&1 | grep -E "Upload|EXPORT|error:" | tail -5
'
```
---
## iOS 部署检查清单
部署前逐项确认:
- [ ] build number 已递增(`CURRENT_PROJECT_VERSION` in project.yml
- [ ] `xcodegen generate` 已运行(新文件已包含在 xcodeproj 中)
- [ ] 代码已 push 到远程仓库
- [ ] 构建机可 SSH 访问
- [ ] Assets.xcassets 包含 1024x1024 App Icon
- [ ] Info.plist 包含 iPad 四方向支持
- [ ] Distribution 证书已安装在构建机 Keychain
部署后逐项确认:
- [ ] Archive 成功
- [ ] Export + Upload 成功
- [ ] 合规信息已设置usesNonExemptEncryption
- [ ] 测试说明已填写whatsNew
- [ ] Build 已关联到 App Store 版本
- [ ] TestFlight 状态为 IN_BETA_TESTING
- [ ] 测试者收到更新通知
---
## Docker Staging/Production 部署
### 架构概览
```
develop push → Build Image → Push ACR → SSH Deploy (staging) → Health Check
main push → Build Image → Push ACR → 人工审批 → SSH Deploy (prod) → Health Check
```
| 组件 | 说明 |
|------|------|
| 服务器 | 39.104.87.246(阿里云 ECS |
| Registry | Aliyun ACR: `crpi-q4nnuivosic0zc98.cn-beijing.personal.cr.aliyuncs.com` |
| 镜像 | `xiaoqu-gateway`, `xiaoqu-web` |
| SSH Key | `~/.ssh/xiaoqu.pem` |
| 部署方式 | Docker Compose |
### 完整部署流程
```
1. 本地构建镜像 → docker build -t <image>:<tag>
2. 推送到 ACR → docker push <registry>/<image>:<tag>
3. SSH 到服务器 → docker compose pull + up -d
4. 健康检查 → curl /health
5. 通知 → 飞书 Webhook 发送部署结果
```
### Staging 部署develop 分支自动触发)
Push 到 `develop` 分支自动触发 staging 部署。流程:
```bash
# 1. 构建镜像tag 用 commit SHA 前 8 位)
TAG=$(git rev-parse --short=8 HEAD)
REGISTRY=crpi-q4nnuivosic0zc98.cn-beijing.personal.cr.aliyuncs.com
docker build -t $REGISTRY/xiaoqu-gateway:$TAG -f gateway/Dockerfile .
docker build -t $REGISTRY/xiaoqu-web:$TAG -f web/Dockerfile .
# 2. 推送到 ACR
docker push $REGISTRY/xiaoqu-gateway:$TAG
docker push $REGISTRY/xiaoqu-web:$TAG
# 3. SSH 部署
ssh -i ~/.ssh/xiaoqu.pem root@39.104.87.246 "
cd /opt/xiaoqu/staging
export IMAGE_TAG=$TAG
docker compose pull
docker compose up -d
"
# 4. 健康检查
sleep 10
curl -sf http://39.104.87.246:8080/health || echo 'Health check failed!'
```
### Production 部署(手动审批)
Production 部署需要人工确认,不会自动触发:
```bash
# 使用 build-and-push 脚本
./scripts/build-and-push.sh prod --detect --deploy --wait --verify
# 或手动执行:
TAG=v1.2.3 # 使用语义化版本号
REGISTRY=crpi-q4nnuivosic0zc98.cn-beijing.personal.cr.aliyuncs.com
# 构建 + 推送
docker build -t $REGISTRY/xiaoqu-gateway:$TAG -f gateway/Dockerfile .
docker build -t $REGISTRY/xiaoqu-web:$TAG -f web/Dockerfile .
docker push $REGISTRY/xiaoqu-gateway:$TAG
docker push $REGISTRY/xiaoqu-web:$TAG
# 部署(生产环境目录)
ssh -i ~/.ssh/xiaoqu.pem root@39.104.87.246 "
cd /opt/xiaoqu/production
export IMAGE_TAG=$TAG
docker compose pull
docker compose up -d
"
# 验证
curl -sf http://39.104.87.246/health && echo 'Production deploy OK'
```
### build-and-push 脚本模板
```bash
#!/bin/bash
# scripts/build-and-push.sh
set -euo pipefail
ENV=${1:-staging}
REGISTRY=crpi-q4nnuivosic0zc98.cn-beijing.personal.cr.aliyuncs.com
SERVER=39.104.87.246
SSH_KEY=~/.ssh/xiaoqu.pem
IMAGES=(xiaoqu-gateway xiaoqu-web)
# 确定 tag
if [ "$ENV" = "prod" ]; then
TAG=${2:-$(git describe --tags --abbrev=0)}
else
TAG=$(git rev-parse --short=8 HEAD)
fi
echo "=== Deploying to $ENV with tag $TAG ==="
# 构建
for img in "${IMAGES[@]}"; do
echo "Building $img..."
docker build -t $REGISTRY/$img:$TAG -f ${img#xiaoqu-}/Dockerfile .
done
# 推送
for img in "${IMAGES[@]}"; do
echo "Pushing $img..."
docker push $REGISTRY/$img:$TAG
done
# 部署
DEPLOY_DIR=/opt/xiaoqu/$ENV
ssh -i $SSH_KEY root@$SERVER "
cd $DEPLOY_DIR
export IMAGE_TAG=$TAG
docker compose pull
docker compose up -d --remove-orphans
"
# 健康检查(重试 3 次)
echo "Waiting for health check..."
for i in 1 2 3; do
sleep 5
if curl -sf http://$SERVER/health > /dev/null 2>&1; then
echo "✓ Health check passed"
exit 0
fi
echo "Attempt $i failed, retrying..."
done
echo "✗ Health check failed after 3 attempts"
exit 1
```
### Docker Compose 示例
```yaml
# docker-compose.yml
version: "3.8"
services:
gateway:
image: crpi-q4nnuivosic0zc98.cn-beijing.personal.cr.aliyuncs.com/xiaoqu-gateway:${IMAGE_TAG:-latest}
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgres://...
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
web:
image: crpi-q4nnuivosic0zc98.cn-beijing.personal.cr.aliyuncs.com/xiaoqu-web:${IMAGE_TAG:-latest}
ports:
- "3000:3000"
depends_on:
gateway:
condition: service_healthy
restart: unless-stopped
```
---
## 部署前健康检查
部署前进行预检,避免部署失败浪费时间。
### iOS 预检
```bash
preflight_ios() {
local errors=0
# 检查 Distribution 证书
if ! security find-identity -v -p codesigning | grep -q "Apple Distribution"; then
echo "ERROR: Apple Distribution 证书未安装"
((errors++))
fi
# 检查 Provisioning Profile 有效期
local profile_dir="$HOME/Library/MobileDevice/Provisioning Profiles"
if [ -d "$profile_dir" ]; then
for profile in "$profile_dir"/*.mobileprovision; do
local expiry
expiry=$(security cms -D -i "$profile" 2>/dev/null | plutil -extract ExpirationDate raw - 2>/dev/null)
if [ -n "$expiry" ]; then
local expiry_epoch
expiry_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$expiry" "+%s" 2>/dev/null)
local now_epoch
now_epoch=$(date "+%s")
if [ "$expiry_epoch" -lt "$now_epoch" ]; then
echo "WARNING: Profile 已过期: $(basename "$profile")"
((errors++))
fi
fi
done
else
echo "ERROR: Provisioning Profiles 目录不存在"
((errors++))
fi
# 检查 API Key
if [ ! -f "${API_KEY_PATH:-/dev/null}" ]; then
echo "ERROR: ASC API Key (.p8) 文件不存在: $API_KEY_PATH"
((errors++))
fi
# 检查 Xcode
if ! xcode-select -p > /dev/null 2>&1; then
echo "ERROR: Xcode Command Line Tools 未安装"
((errors++))
fi
if [ $errors -gt 0 ]; then
echo "iOS 预检失败: $errors 个问题"
return 1
fi
echo "iOS 预检通过"
return 0
}
```
### Docker 预检
```bash
preflight_docker() {
local errors=0
# 检查 Docker daemon
if ! docker info > /dev/null 2>&1; then
echo "ERROR: Docker daemon 未运行"
((errors++))
fi
# 检查 ACR registry 可达
local registry=crpi-q4nnuivosic0zc98.cn-beijing.personal.cr.aliyuncs.com
if ! docker login $registry --username dummy --password dummy 2>&1 | grep -qv "connection refused"; then
# login 会失败但不应该是 connection refused
echo "WARNING: ACR registry 可能不可达(将在 push 时验证)"
fi
# 检查 SSH 连通性
if ! ssh -i ~/.ssh/xiaoqu.pem -o ConnectTimeout=5 -o BatchMode=yes root@39.104.87.246 "echo ok" > /dev/null 2>&1; then
echo "ERROR: 无法 SSH 连接到部署服务器 39.104.87.246"
((errors++))
fi
# 检查服务器磁盘空间
local disk_usage
disk_usage=$(ssh -i ~/.ssh/xiaoqu.pem root@39.104.87.246 "df -h / | tail -1 | awk '{print \$5}' | tr -d '%'" 2>/dev/null)
if [ -n "$disk_usage" ] && [ "$disk_usage" -gt 85 ]; then
echo "WARNING: 服务器磁盘使用率 ${disk_usage}%(建议清理 docker system prune"
fi
# 检查本地磁盘空间
local local_disk
local_disk=$(df -h . | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$local_disk" -gt 90 ]; then
echo "ERROR: 本地磁盘使用率 ${local_disk}%,空间不足"
((errors++))
fi
if [ $errors -gt 0 ]; then
echo "Docker 预检失败: $errors 个问题"
return 1
fi
echo "Docker 预检通过"
return 0
}
```
---
## 回滚策略
### iOS TestFlight 回滚
TestFlight **无法真正回滚**已安装的版本,但有以下应急手段:
| 手段 | 说明 | API |
|------|------|-----|
| 停止分发 | 将 build 从测试中移除,用户不再收到更新 | `PATCH /v1/builds/{id}` 设置 `expired: true` |
| 过期 build | 强制过期有问题的 build | 同上 |
| 紧急热修 | 构建新版本覆盖上线 | 常规部署流程 |
```bash
# 通过 ASC API 停止分发某个 build
curl -X PATCH "https://api.appstoreconnect.apple.com/v1/builds/$BUILD_ID" \
-H "Authorization: Bearer $JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"data":{"type":"builds","id":"'$BUILD_ID'","attributes":{"expired":true}}}'
```
### Docker 回滚
Docker 回滚相对简单,拉取上一个正常版本的镜像重新部署即可:
```bash
# 1. 确定上一个正常的 tag
PREVIOUS_TAG=<previous-good-tag>
REGISTRY=crpi-q4nnuivosic0zc98.cn-beijing.personal.cr.aliyuncs.com
# 2. 在服务器上回滚
ssh -i ~/.ssh/xiaoqu.pem root@39.104.87.246 "
cd /opt/xiaoqu/production # 或 /opt/xiaoqu/staging
export IMAGE_TAG=$PREVIOUS_TAG
docker compose pull
docker compose up -d
"
# 3. 验证回滚成功
curl -sf http://39.104.87.246/health && echo 'Rollback OK'
```
### 数据库回滚注意事项
| 场景 | 策略 |
|------|------|
| 可逆 migration加列、加表 | 部署回滚后数据库无需回滚,旧代码忽略新列 |
| 不可逆 migration删列、改类型 | **必须先回滚 migration 再回滚代码**,否则旧代码报错 |
| 数据 migration | 评估是否需要补偿脚本,建议 migration 前做备份快照 |
```bash
# 数据库 migration 回滚示例(如果使用 golang-migrate
ssh -i ~/.ssh/xiaoqu.pem root@39.104.87.246 "
docker compose exec gateway migrate -path /migrations -database \$DATABASE_URL down 1
"
```
---
## 部署监控
### Post-deploy 健康检查模式
```bash
# 通用部署后验证函数
post_deploy_verify() {
local url=$1
local max_retries=${2:-5}
local interval=${3:-10}
echo "Verifying deployment at $url ..."
for i in $(seq 1 $max_retries); do
local status
status=$(curl -sf -o /dev/null -w "%{http_code}" "$url" 2>/dev/null || echo "000")
if [ "$status" = "200" ]; then
echo "Health check passed (attempt $i/$max_retries)"
return 0
fi
echo "Attempt $i/$max_retries: status=$status, retrying in ${interval}s..."
sleep $interval
done
echo "Health check FAILED after $max_retries attempts"
return 1
}
# 使用示例
post_deploy_verify "http://39.104.87.246/health" 5 10
```
### 飞书通知模板
部署完成后通过飞书 Webhook 发送通知:
```bash
# 部署成功通知
send_feishu_deploy_notification() {
local env=$1 # staging / production
local version=$2 # 版本号或 tag
local status=$3 # success / failure
local detail=$4 # 额外说明
local WEBHOOK_URL="<飞书群 Webhook 地址>"
if [ "$status" = "success" ]; then
local color="green"
local emoji="✅"
else
local color="red"
local emoji="❌"
fi
curl -s -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d '{
"msg_type": "interactive",
"card": {
"header": {
"title": {"tag": "plain_text", "content": "'"$emoji"' 部署通知 - '"$env"'"},
"template": "'"$color"'"
},
"elements": [
{"tag": "div", "text": {"tag": "lark_md", "content": "**环境**: '"$env"'\n**版本**: '"$version"'\n**状态**: '"$status"'\n**时间**: '"$(date '+%Y-%m-%d %H:%M:%S')"'\n**详情**: '"$detail"'"}}
]
}
}'
}
# 使用示例
send_feishu_deploy_notification "production" "v1.2.3" "success" "Gateway + Web 部署完成"
send_feishu_deploy_notification "staging" "abc12345" "failure" "Health check 超时"
```
### iOS TestFlight 构建状态监控
通过 ASC API 持续监控 build 处理状态:
```bash
# 监控 TestFlight build 处理状态
monitor_testflight_build() {
local build_id=$1
local jwt_token=$2
local max_wait=600 # 最长等待 10 分钟
local elapsed=0
while [ $elapsed -lt $max_wait ]; do
local response
response=$(curl -s "https://api.appstoreconnect.apple.com/v1/builds/$build_id" \
-H "Authorization: Bearer $jwt_token")
local state
state=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['attributes']['processingState'])" 2>/dev/null)
echo "[$(date '+%H:%M:%S')] Build $build_id: $state"
case "$state" in
VALID)
echo "Build 处理完成,可用于测试"
return 0
;;
FAILED|INVALID)
echo "Build 处理失败: $state"
return 1
;;
PROCESSING)
sleep 30
((elapsed+=30))
;;
*)
sleep 15
((elapsed+=15))
;;
esac
done
echo "Build 处理超时(${max_wait}s"
return 1
}
```
---
## 与需求工作流集成
部署完成后更新需求状态:
```bash
# 推进到 released
ai-proj req advance --id <req_id> --to released
# 创建部署任务并关联
ai-proj task create --title "【部署】TestFlight 发布: {需求标题}"
ai-proj req link --id <req_id> --task-ids <task_id>
# 附加部署文档
ai-proj task append-doc --id <task_id> --content "部署记录..."
```
---
## 经验教训汇总
### iOS TestFlight 部署的 10 个坑
| # | 坑 | 解决方案 |
|---|-----|---------|
| 1 | SSH 远程 codesign 失败 | `unlock-keychain` + `set-key-partition-list` |
| 2 | SPM 依赖报签名错误 | Archive 阶段 `CODE_SIGNING_ALLOWED=NO`Export 阶段签名 |
| 3 | Swift Macros 被拒 | `-skipMacroValidation` |
| 4 | xcodeproj 缺文件 | 新增源文件后必须 `xcodegen generate` |
| 5 | 无 Distribution 证书 | Xcode > Accounts 登录 Apple ID 自动下载 |
| 6 | build number 冲突 | 每次部署前递增 `CURRENT_PROJECT_VERSION` |
| 7 | 缺 App Icon | Assets.xcassets + AppIcon.appiconset + 1024x1024 PNG |
| 8 | iPad 方向验证失败 | 声明四方向或 `UIRequiresFullScreen=true` |
| 9 | ASC API 401 | JWT 必须包含 `kid` header + 正确的 Issuer ID |
| 10 | App Store 图标为空 | 需将 build 关联到 App Store 版本PATCH relationships/build |
| 11 | SSH 长连接断开 | xcodebuild 3-4 分钟无输出Tailscale 断连。用 nohup 后台执行 |
| 12 | xcodegen 后 cwd 错乱 | `cd ios && xcodegen && cd ..` 失败时不回退。用 subshell `(cd ios && xcodegen)` |

View File

@@ -0,0 +1,8 @@
{
"name": "dev-integration-plugin",
"description": "前后端联调技能。API 契约验证、联调报告、纯后端需求自动跳过。对应 req 流程 integration 阶段。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,154 @@
---
name: dev-integration
description: 前后端联调技能。API 契约验证、接口对接、联调报告生成。对应 req 流程 integration 阶段。纯后端需求自动跳过。
---
# 前后端联调 Skill (dev-integration)
## 概述
本技能用于前后端联调阶段,确保实际实现与 API 契约一致。
**核心价值**:发现契约偏差(字段名不一致、类型不匹配、缺少错误码处理)比测试阶段更早、修复成本更低。
---
## 技能间契约
| 上游 | 本技能输入 | 本技能输出 | 下游 |
|------|-----------|-----------|------|
| dev-coding | 已实现的前后端代码 + API 契约(来自 req-design | 联调报告(通过/不通过 + 问题列表) | dev-test |
---
## 自动跳过条件
以下情况 integration 阶段**自动通过**,无需执行联调:
| 条件 | 原因 |
|------|------|
| 需求只有后端 implementation 任务(无前端任务) | 没有前端对接,无需联调 |
| 需求只有前端 implementation 任务(无后端任务) | 使用已有 API无需联调 |
| 需求无 implementation 任务(纯 skill/ops/doc | 非代码需求 |
**检测方法**
```
get_requirement_tasks → 检查 linkRole=implementation 的任务标题
含【开发-后端】和【开发-前端】→ 需要联调
仅含一端 → 自动跳过
```
---
## 工作流程
```
1. 检查是否需要联调
├── 获取 implementation 任务列表
├── 判断是否有前后端双端任务
└── 仅单端 → 自动跳过,生成跳过说明
2. 获取 API 契约
├── 从 req-design 文档中提取 API 契约
└── 无契约 → 从代码反推接口定义
3. 契约验证
├── 后端实际接口 vs 契约定义
│ ├── URL 路径是否一致
│ ├── 请求/响应字段名是否一致
│ ├── 字段类型是否匹配
│ └── 错误码是否完整
├── 前端调用 vs 契约定义
│ ├── API service 调用路径是否正确
│ ├── 请求参数是否完整
│ └── 响应处理是否覆盖所有错误码
└── 前端 ↔ 后端一致性
├── 字段命名一致camelCase vs snake_case 转换)
└── 分页参数格式一致
4. 功能对接验证
├── 前端表单字段 vs 后端 binding 规则
├── 前端列表列 vs 后端响应字段
└── 前端状态流转 vs 后端状态机
5. 生成联调报告
├── 契约一致性结果
├── 发现的偏差列表
└── 结论:通过/不通过
```
---
## 联调报告模板
```markdown
## 联调报告 — {需求标题}
**日期**: YYYY-MM-DD
**API 契约来源**: {req-design 文档 / 代码反推}
### 契约验证结果
| # | 接口 | 契约 | 后端实际 | 前端调用 | 结果 |
|---|------|------|---------|---------|------|
| 1 | POST /api/v1/xxx | ✅ 已定义 | ✅ 一致 | ✅ 一致 | PASS |
| 2 | GET /api/v1/xxx | ✅ 已定义 | ⚠️ 字段名不一致 | ✅ 一致 | FAIL |
### 发现的偏差
| # | 类型 | 接口 | 描述 | 影响 | 建议 |
|---|------|------|------|------|------|
| 1 | 字段名不一致 | GET /api/v1/xxx | 契约定义 `created_at`,后端返回 `createTime` | 前端解析失败 | 统一为 `created_at` |
### 结论
**{通过 / 不通过}**
{如不通过,列出必须修复的偏差编号}
```
---
## 插件支持
| 插件 | 触发条件 | 说明 |
|------|---------|------|
| `api-contract-verify` | 有 API 变更 | 自动化契约验证(未来) |
---
## 与 ai-proj 集成
### req 流程内
```typescript
// 创建联调任务(如需要)
mcp__ai-proj__create_task({ title: "【联调】前后端对接: {需求标题}" })
mcp__ai-proj__link_tasks_to_requirement({
requirementId, taskIds: [taskId], linkRole: "implementation"
})
// 附加联调报告
mcp__ai-proj__create-and-attach({
taskId, title: "联调报告", content: "<报告内容>"
})
```
### 自动跳过时
```typescript
// 记录跳过原因
mcp__ai-proj__create-and-attach({
taskId: <设计任务ID>,
content: "## 联调阶段\n\n自动跳过仅后端变更无前端对接。"
})
```
---
## 最佳实践
1. **契约先行** — API 契约是联调的基准,没有契约就先补
2. **字段级验证** — 不只检查接口是否通,要检查每个字段名、类型、格式
3. **错误码覆盖** — 前端必须处理契约中定义的所有错误码
4. **snake_case 转换** — Go 后端用 snake_case前端用 camelCase确认自动转换正确

View File

@@ -0,0 +1 @@
{"name":"dev-ios-plugin","description":"iOS 开发插件。Swift/SwiftUI + MVVM 架构、TestFlight 部署、Xcode 构建。按需加载。","version":"1.0.0","author":{"name":"qiudl"}}

View File

@@ -0,0 +1,90 @@
---
name: dev-ios
description: iOS 开发插件。Swift/SwiftUI + MVVM 架构TestFlight 部署。当涉及 iOS 开发任务时按需加载。
---
# iOS 开发插件 (dev-ios)
## 架构SwiftUI + MVVM
```
AI-Proj-iOS/
├── Core/ # 核心层
│ ├── Architecture/ # AppCoordinator, AppState
│ ├── Components/ # 通用 UI 组件
│ ├── Config.swift # 配置
│ ├── Services/ # APIEndpoints, AuthService, NetworkService, DIContainer
│ ├── Theme/ # 主题配置
│ └── Utilities/ # 设备适配
├── Features/ # 功能模块MVVM
│ └── Requirements/ # 示例List/Detail View + ViewModel
├── Models/ # 数据模型 + DTOs
└── Resources/ # Assets
```
**开发顺序**Model → DTO → APIEndpoints → ServiceProtocols → ViewModel → View
## 代码规范
```swift
@MainActor
class TaskViewModel: ObservableObject {
@Published private(set) var tasks: [Task] = []
@Published private(set) var isLoading = false
@Published var error: String?
private let taskService: TaskServiceProtocol
init(taskService: TaskServiceProtocol) {
self.taskService = taskService
}
func loadTasks() async {
guard !isLoading else { return }
isLoading = true
defer { isLoading = false }
do {
tasks = try await taskService.fetchTasks()
} catch {
self.error = error.localizedDescription
}
}
}
```
**规则**
- ViewModel 使用 `@MainActor`
- Published 属性用 `private(set)`
- 使用协议依赖注入
- `async/await` 而非 completion handler
- `guard` 提前返回,`defer` 确保状态重置
## 命名规范
| 类型 | 规范 | 示例 |
|------|------|------|
| 文件/类 | 大驼峰 | `ManualListView.swift` |
| 协议 | 大驼峰 + Protocol | `ManualServiceProtocol` |
| 函数/变量 | 小驼峰 | `loadManuals()`, `isLoading` |
| 枚举 case | 小驼峰 | `case draft` |
## 构建与部署
```bash
# 构建
xcodebuild -scheme AI-Proj-iOS -configuration Debug
# 测试
xcodebuild test -scheme AI-Proj-iOS
# TestFlight 部署详见 memory: testflight-deploy.md
```
## 常见问题
### SwiftLint 沙盒错误
Xcode 15+ 默认启用 User Script Sandboxing → Build Settings → `ENABLE_USER_SCRIPT_SANDBOXING = NO`
### Personal Team 功能限制
免费账户不支持 Push Notifications / Associated Domains / App Groups → 从 Entitlements 中移除

View File

@@ -0,0 +1 @@
{"name":"dev-mcp-plugin","description":"MCP Bridge 开发插件。TypeScript MCP 服务开发、Token 管理、HTTP 客户端模式。按需加载。","version":"1.0.0","author":{"name":"qiudl"}}

View File

@@ -0,0 +1,59 @@
---
name: dev-mcp
description: MCP Bridge 开发插件。TypeScript MCP 服务开发Token 管理HTTP 客户端模式。当涉及 mcp-task-bridge 开发时按需加载。
---
# MCP Bridge 开发插件 (dev-mcp)
## 项目结构
```
mcp-task-bridge/
├── index.ts # 入口MCP server 注册
├── task-service.ts # 任务服务
├── document-service.ts # 文档服务
├── requirement-service.ts # 需求服务
├── base-client.ts # HTTP 基类(认证、重试)
├── types.ts # 类型定义
└── token-storage.ts # Token 持久化
```
## 代码规范
```typescript
export class TaskService extends BaseClient {
async createTask(
title: string,
projectId: number = 1,
options: CreateTaskOptions = {}
): Promise<ApiResponse<Task>> {
try {
const response = await this.makeRequest<Task>(
'POST',
`/projects/${projectId}/tasks`,
{ title, project_id: projectId, ...options }
);
return response.success
? { success: true, data: response.data, message: `✅ 任务创建成功` }
: response;
} catch (error: any) {
return { success: false, error: `创建任务失败: ${error.message}` };
}
}
}
```
## 关键规则
1. **MCP endpoint 前缀**:所有 MCP 专用后端接口必须包含 `/mcp/` 前缀
2. **修改后重新构建**`npm run build``pkill -f "mcp-task-bridge/dist/index.js"`
3. **环境一致性**不要跨环境混用数据dev/staging/prod
## 常用命令
```bash
npm run dev # 开发hot reload
npm run build # 编译 TypeScript
npm test # 快速测试
npm run test:integration # 集成测试
```

View File

@@ -0,0 +1 @@
{"name":"dev-pda-plugin","description":"PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先模式。按需加载。","version":"1.0.0","author":{"name":"qiudl"}}

View File

@@ -0,0 +1,49 @@
---
name: dev-pda
description: PDA 应用开发插件。Android 原生 + 扫码枪集成 + 离线优先。当涉及 PDA/手持终端开发时按需加载。
---
# PDA 应用开发插件 (dev-pda)
## 特点
- Android 原生开发Kotlin
- 扫码枪硬件集成
- 离线优先(本地 Room DB + 同步队列)
- 简洁 UI大按钮、大字体、适配小屏幕
## 扫码集成
```kotlin
class ScanReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val barcode = intent.getStringExtra("SCAN_BARCODE")
// 处理扫码结果
}
}
```
## 离线存储
```kotlin
@Entity(tableName = "inventory")
data class Inventory(
@PrimaryKey val id: Long,
val barcode: String,
val quantity: Int,
@ColumnInfo(name = "sync_status")
val syncStatus: SyncStatus = SyncStatus.PENDING
)
enum class SyncStatus { PENDING, SYNCED, FAILED }
```
## 离线同步策略
```
操作 → 写入本地 DB (PENDING)
网络可用 → 批量上传 → 成功 → 标记 SYNCED
↓ 失败
标记 FAILED → 下次重试
```

View File

@@ -0,0 +1,8 @@
{
"name": "dev-review-plugin",
"description": "代码评审技能。五视角对抗性扫描法(攻击者/泄露者/并发者/边界者/依赖者CR 报告生成,独立于 req 工作流可单独使用。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,280 @@
---
name: dev-review
description: 代码评审技能。五视角对抗性扫描法,用于 PR 代码审查、安全评审、质量检查。当执行 /req cr 或独立 PR review 时自动激活。
---
# 代码评审 Skill (dev-review)
## 概述
独立的代码评审技能,核心方法论是**五视角对抗性扫描法**。
**适用场景**
- `/req cr [REQ-ID]` — 需求流程中的代码评审阶段
- 独立 PR review — 不绑定需求的代码审查
- 安全评审 — 专项安全扫描
**核心原则**:实现阶段关注"怎么让它跑通",评审阶段关注**"怎么让它出错"**。AI 必须切换到对抗性思维。
---
## 技能间契约
| 上游 | 本技能输入 | 本技能输出 | 下游 |
|------|-----------|-----------|------|
| dev-coding | PR diff + 开发设计文档 | CR 报告(五视角扫描 + 发现汇总 + 结论) | dev-test |
---
## 工作流程
```
1. 确定评审范围
├── git diff 获取变更文件列表
├── 统计文件数、行数
└── 排除 test 文件(单独审查)
2. 读取变更代码
├── 逐个读取变更<E58F98><E69BB4><EFBFBD>件源码
├── 理解业务上下文
└── 参考开发设计文档(如有)
3. 五视角扫描(核心)
├── 攻击<E694BB><E587BB><EFBFBD>视角
├── 泄露者视角
├── 并发者视角
├── 边界者视角
└── 依赖者视角
4. 加载项目检查清单(如有)
└── review-checklist 插件
5. 生成 CR 报告
├── 变更概要
├── 五视角扫描结果
├── 发现汇总表
└── 结论(通过/有条件通过/需修改)
6. 创建评审任务req 流程内)
├── ai-proj task create【代码评审】
├── 关联需求linkRole=code_review
└── 附加 CR 报告文档
7. 处理发现
├── Critical/High → 创建修复任务
└── Medium/Low → 记录建议
```
---
## 五视角对抗性扫描法
### 总览
| 视角 | 思维模式 | 核心问题 |
|------|---------|---------|
| **1. 攻击者** | "我怎么绕过/<2F><><EFBFBD>用它" | 跨租户泄露、越权访问、参数注入、重放攻击 |
| **2. 泄露者** | "它暴露了什么不该暴露的?" | 错误信息泄露、日志敏感数据、响应内部细节 |
| **3. 并发者** | "两个请求同时来会怎样?" | 竞态条件、双重扣款、幂等性缺失、锁粒度 |
| **4. 边界者** | "极端输入会怎样?" | 空值/零值/负值/超长字符串、类型溢出、分页越界 |
| **5. 依赖者** | "外部服务挂了会怎样?" | 超时处理、重试策略、降级方案、连接泄露 |
### 视角1攻击者多租户安全
**思维模式**:我是恶意用户,如何绕过权限获取他人数据。
扫描清单:
- [ ] 所有 Store/Repository 层查询是否带 `tenant_id` 过滤?
- [ ] 通过 ID 直接查询的方法是否校验归属?
- [ ] 用户只能操作自己的数据consumer_id 校验)
- [ ] URL/请求参数是否有注入风险SQL、URL、命令注入
- [ ] 外部输入是否直接拼接到查询/URL应使用参数化查询或编码
- [ ] 批量操作是否逐条校验权限?(不能只校验第一条)
- [ ] 文件上传是否有类型/大小限制?
**典型发现示例**
```
file:line — Store.GetByID(id) 缺少 tenant_id 过滤,
攻击者可通过遍<EFBFBD><EFBFBD> ID 获取其他租户数据。
建议:添加 WHERE tenant_id = ? 条件。
```
### 视角2泄露者信息安全
**思维模式**:我是安全审计员,检查每个出口是否泄露了不该泄露的信息。
扫描清单:
- [ ] 错误消息是否泄露业务状态?(如"手机号未注册"暴露用户存在性)
- [ ] 日志是否打印了密码、token、密钥、身份证号
- [ ] 响应是否包含不必要的内部字段?(如内部 ID、数据库字段名、堆栈跟踪
- [ ] panic recover 后是否返回了内部错误详情?
- [ ] 导出/下载功能是否过滤了敏感字段?
### 视角3并发者数据一致性
**思维模式**:两个用户同时操作同一条数据,会发生什么。
扫描清单:
- [ ] 涉及金额/库存变更是否使用事务 + 悲观锁/乐观锁?
- [ ] 关键操作是否有幂等保护bizNo 唯一索引、幂等键)
- [ ] 全局状态(如进程内计数器、缓存)重启后是否安全?
- [ ] 是否有 TOCTOU检查-使用)竞态?(先查状态再操作,中间被修改)
- [ ] 并发创建是否会产生重复数据?(唯一约束)
### 视角4边界者健壮性
**思维模<E7BBB4><E6A8A1>**:用最极端的输入来测试系统的承受能力。
扫描清单:
- [ ] 必填参数是否有 `binding:"required"` 校验?
- [ ] 数值参数是否有范围校验min/max防止负数、溢出
- [ ] 字符串是否有长度限制?(防止超长输入消耗内存)
- [ ] 分页参数是否有默认值和上限page_size 不能为 0 或 999999
- [ ] 数组参数是否有长度限制?(批量操作不能传 10 万条)
- [ ] 空数组/空字符串是否正确处理?(不应触发不必要的数据库操作)
- [ ] 除零错误?百分比计算分母为 0
### 视角5依赖者可靠性
**思维模式**:外部服务全部挂掉,系统还能正常运行吗。
扫描清单:
- [ ] HTTP 客户端是否设置超时connect/read/write timeout
- [ ] 外部 API 调用失败是否有合理的错误处理?(不能直接 panic
- [ ] 是否有重试策略?重试是否有退避?是否幂等安全?
- [ ] 数据库连接池配置是否合理max idle/max open/lifetime
- [ ] Redis 不可用时是否有降级方案?(缓存穿透到数据库)
- [ ] token 过期/刷新逻辑是否正确access vs refresh 不同策略)
---
## CR 报告模板
```markdown
## 代<><E4BBA3>评审报告 — {需求标题/PR 标题}
**日期**: YYYY-MM-DD
**评审范围**: {N} 个文件, {M} 行变更
**评审人**: AI (dev-review)
### 变更概要
{1-3 句描述本次变更的目的和范围}
### 五视角扫描结果
#### 1. 攻击者视角
{扫描发现,或 "未发现问题"}
#### 2. 泄露者视角
{扫描发现,或 "未发现问题"}
#### 3. 并发者视角
{扫描发现,或 "未发现问题"}
#### 4. 边界者视角
{扫描发现,或 "未发现问题"}
#### 5. 依赖者视角
{扫描发现,或 "未发现问题"}
### 审查发现汇总
| # | 严重度 | 文件:行号 | <20><><EFBFBD>角 | 描述 | 建议 |
|---|--------|----------|------|------|------|
| 1 | {Critical/High/Medium/Low} | {file:line} | {视角} | {问题} | {建议} |
### 统计
| 严重度 | 数量 |
|--------|------|
| Critical | 0 |
| High | 0 |
| Medium | 0 |
| Low | 0 |
### 结论
**{通过 / 有条件通过 / 需修改}**
{结论说明:如果有 Critical/High 必须修复后重新评审}
```
---
## 严重度定义
| 严重度 | 含义 | 处理方式 |
|--------|------|---------|
| **Critical** | 安全漏洞、数据泄露、资金风险 | 必须修复,阻断合并 |
| **High** | 数据一致性风险、业务逻辑错误 | 必须修复,阻断合并 |
| **Medium** | 边界未处理、缺少校验、性能隐患 | 建议修复,不阻断 |
| **Low** | 代码风格、命名优化、文档补充 | 可选修复 |
---
## CR 报告质量门禁
`/req next` 从 review 阶段推进时,检查 CR 报告质量:
| 检查项 | 标准 |
|--------|------|
| 文档存在 | CR 任务有附加文档 |
| 字数 | ≥ 500 字 |
| 代码引用 | 含 `file:line` 格式的引用 |
| 五视角扫描 | 含全部 5 个视角章节 |
| 结论章节 | 含明确的通过/不通过结论 |
---
## 插件支持
| 插件 | 触发条件 | 说明 |
|------|---------|------|
| `review-checklist` | 每次 CR | 加载项目特定检查清单 |
| `figma-design-qa` | 有设计稿 | 设计还原度对比 |
---
## 与 ai-proj 集成
### req 流程内(/req cr
```typescript
// 1. 确认 implementation 任务已完成
mcp__ai-proj__get_requirement_tasks({ requirementId })
// 检查所有 linkRole=implementation 的任务状态
// 2. 创建 CR 任务
mcp__ai-proj__create_task({ title: "【代码评审】CR: {需求标题}" })
mcp__ai-proj__link_tasks_to_requirement({
requirementId, taskIds: [crTaskId], linkRole: "code_review"
})
// 3. 附加 CR 报告
mcp__ai-proj__create-and-attach({
taskId: crTaskId,
title: "代码评审报告",
content: "<CR <20><><EFBFBD>告 Markdown>"
})
// 4. High/Critical 发现 → 创建修复任务
mcp__ai-proj__create_task({ title: "【修复】{问题描述}" })
mcp__ai-proj__link_tasks_to_requirement({
requirementId, taskIds: [fixTaskId], linkRole: "implementation"
})
```
### 独立 PR review
不需要 ai-proj 集成,直接输出 CR 报告到对话。
---
## 最佳实践
1. **先理解再审查** — 读完所有变更<E58F98><E69BB4><EFBFBD>件后再开始扫描避免断章取义
2. **对抗性思维** — 切换到"怎么让它出错"的心态,不是"怎么让它跑通"
3. **证据驱动** — 每个发现必须引用具体的 `file:line`
4. **严重度准确** — 不要所有问题都标 High按实际影响分级
5. **建议可操作** — 每个发现必须附带具体修复建议
6. **关注变更** — 评审范围是 diff不要对未变更的代码提意见除非变更引入了对旧代码的新风险

View File

@@ -0,0 +1,6 @@
{
"name": "dev-scaffold-plugin",
"description": "模块脚手架插件。新建模块时自动生成分层代码骨架Model/Repository/Service/Handler/Route。挂载在 dev 阶段。",
"version": "1.0.0",
"author": { "name": "qiudl" }
}

View File

@@ -0,0 +1,78 @@
---
name: dev-scaffold
description: 模块脚手架插件。新建模块时自动生成分层代码骨架。挂载在 dev 阶段,新建模块时激活。
---
# 模块脚手架插件 (dev-scaffold)
## 概述
当需要新建一个完整模块时,自动生成分层代码骨架,避免手动创建大量样板文件。
**触发条件**
- 需求需要新建数据库表 + 完整 CRUD
- 开发设计文档中有"新增"类型的文件
## Go 后端脚手架
输入模块名(如 `manual`),生成以下文件:
```
backend/
├── models/manual.go # GORM 模型
├── database/manual_repository.go # Repository
├── services/manual_service.go # Service
├── handlers/manual_handler.go # Handler
├── routes/manual_routes.go # Route
└── migrations/YYYYMMDDHHMMSS_create_manual.up.sql # Migration
```
### 生成规则
**Model** (`models/{name}.go`):
- struct 定义 + GORM tags
- TableName() 方法
- 标准字段ID, TenantID, CreatedBy, CreatedAt, UpdatedAt, DeletedAt
**Repository** (`database/{name}_repository.go`):
- interface 定义
- Create, GetByID, List(分页), Update, Delete 方法
- 所有查询带 tenant_id 过滤
**Service** (`services/{name}_service.go`):
- interface 定义
- 注入 Repository
- 基础 CRUD + 业务校验
**Handler** (`handlers/{name}_handler.go`):
- Create, Get, List, Update, Delete 方法
- 请求参数绑定 + 验证
- 统一错误处理
**Route** (`routes/{name}_routes.go`):
- RESTful 路由注册
- Auth 中间件
**Migration** (`migrations/YYYYMMDDHHMMSS_create_{name}.up.sql`):
- CREATE TABLE + 标准字段 + 索引
## React 前端脚手架
输入模块名(如 `Manual`),生成:
```
frontend/src/
├── types/manual.ts # TypeScript 类型
├── services/manualService.ts # API Service
├── pages/ManualListPage.tsx # 列表页
└── pages/ManualDetailPage.tsx # 详情页(可选)
```
## 使用方式
```
用户: "新建 manual 模块的脚手架"
AI: 根据 req-design 的变更文件清单,生成所有骨架文件
```
**注意**:脚手架只生成骨架,具体业务逻辑需在骨架基础上补充。

View File

@@ -14,6 +14,8 @@ description: 软件测试技能。用于单元测试、集成测试、E2E测试
| `ios-testing.md` | iOS 测试 (XCTest + Swift Concurrency) |
| `android-testing.md` | Android 测试 (JUnit + Espresso + Compose) |
| `e2e-testing.md` | E2E PlaywrightAPI Mock 冒烟测试(无后端)+ 全链路集成测试 |
| `templates/go-integration-test.md` | Go 集成测试模板(多步骤 API 流程、中间件验证、租户隔离) |
| `templates/pdv-smoke-spec.md` | PDV 部署后验收 Playwright 模板页面可达、菜单可见、API 连通) |
---
@@ -49,6 +51,7 @@ description: 软件测试技能。用于单元测试、集成测试、E2E测试
| E2E (Mock 冒烟) | `npm run test:e2e:smoke-mock` | `e2e-testing.md` §API Mock |
| E2E (全链路) | `npm run test:e2e` | `e2e-testing.md` §全链路 |
| E2E (Coolbuy PaaS) | `make e2e` | `e2e-testing.md` §Coolbuy |
| E2E (部署后验收 PDV) | `E2E_BASE_URL=<url> npx playwright test e2e/pdv/` | §PDV |
---
@@ -141,3 +144,74 @@ ai-proj task append-doc --id <taskId> --content "# 测试报告
7. **Mock 仅限 Handler 层** - handler 层可以 mock biz 接口 + httptest
8. **E2E 冒烟测试必须用 API Mock** - E2E 门禁不能依赖后端,否则形同虚设。用 `page.route()` 拦截 API`e2e-testing.md`。质量门禁流程Gates 1-5定义在 `req-test-gate` 技能中
9. **李宁测试用例** - Excel 导出见 `coolbuy-legacy` 技能的 `test-cases-excel.md`
---
## 部署后 E2E 验收 (PDV — Post-Deploy Verification)
部署后验收是独立于 TG4 的 E2E 冒烟模式,在 `/req deploy` 健康检查通过后执行。
### PDV vs TG4 区别
| 维度 | TG4 (开发阶段 E2E 冒烟) | PDV (部署后验收) |
|------|------------------------|-----------------|
| **触发时机** | `/req test` Gate 4 | `/req deploy` 步骤 6 |
| **环境** | 本地开发环境API Mock | 真实部署环境 (staging/prod) |
| **目的** | 验证前端逻辑、UI 渲染 | 验证功能入口可达、基本可用 |
| **API** | `page.route()` 拦截 | 真实后端 API |
| **范围** | 回归冒烟 | 仅新功能可达性 |
### PDV 检查项
| 检查项 | 说明 | 示例 |
|--------|------|------|
| **页面可达** | 需求涉及的前端页面返回 200 | `/okr/my`, `/okr/team` |
| **菜单可见** | 新增菜单项在侧栏中出现 | OKR 菜单对目标用户角色可见 |
| **基础渲染** | 页面无白屏/JS 报错 | 页面有预期的标题/组件 |
| **API 连通** | 关键 API 带 token 调用返回正常 | `GET /api/v1/okr/objectives` 返回 200 |
### PDV 不做什么
- 不做完整回归测试(那是 TG4 的事)
- 不测试复杂业务流程(如多步骤表单提交)
- 不替代手动验收
- 只做「功能入口可达 + 基本可用」的冒烟验证
### PDV 执行方式
```bash
E2E_BASE_URL=<部署环境URL> npx playwright test e2e/pdv/ --project=chromium
```
### PDV Spec 生成规则
AI 根据需求变更范围动态生成 Playwright spec模板见 `templates/pdv-smoke-spec.md`。生成流程:
1. 从需求关联任务提取前端变更范围页面路由、菜单项、API 端点)
2. 登录测试账号(使用 storageState 或手动登录)
3. 验证新增菜单项可见(检查 `.ant-menu` 包含目标文本)
4. 导航到新页面验证非白屏title 不含 error/500/404
5. 调用关键 API验证返回状态码 < 500
6. 每步截图保存为证据
### PDV 结果判定
- **全部 PASS** → 继续推进到 released
- **任一 FAIL** → 阻断推进,在部署文档记录失败项,通知修复
---
## TG2 集成测试检测
### 模板映射
| 变更范围 | 测试输出位置 | 模板 |
|----------|-------------|------|
| 单个 handler 或 service | `*_test.go` (同目录) | `go-testing.md` |
| handlers/ + middleware/ + routes/ (同一功能) | `tests/{feature}_integration_test.go` | `templates/go-integration-test.md` |
### 检测规则
若 git diff 显示同一功能的 `handlers/``middleware/``routes/` 文件均有变更(通过命名模式识别,如 `impersonation_handler.go` + `impersonation_middleware.go` + `impersonation_routes.go`),则除单元测试外**额外生成** `backend/tests/` 下的集成测试。
识别方式:提取文件名中的功能前缀(如 `impersonation`),若在三个目录中均出现,则触发集成测试生成。

View File

@@ -1,14 +1,17 @@
# E2E 测试 (Playwright)
## 种 E2E 测试模式
## 种 E2E 测试模式
| 模式 | 后端依赖 | 速度 | 适用场景 | 门禁阶段 |
|------|---------|------|---------|---------|
| **API Mock 冒烟测试** | ❌ 无需后端 | 快(<30s | UI 布局、路由、菜单、权限隔离 | E2E 冒烟门禁 |
| **API Mock 冒烟测试** | ❌ 无需后端 | 快(<30s | UI 布局、路由、菜单、权限隔离 | TG4 E2E 冒烟门禁 |
| **全链路集成测试** | ✅ 需完整后端+DB | 慢(分钟级) | CRUD 业务流程、数据持久化 | 手动/CI |
| **部署后验收 (PDV)** | ✅ 真实部署环境 | 中(<2min | 功能入口可达、菜单可见、API 连通 | `/req deploy` 步骤 6 |
**⚠️ 关键原则E2E 冒烟门禁必须使用 API Mock 模式,不依赖后端。** 依赖后端的 E2E 在开发机上经常跑不通后端没启动、DB 未初始化),导致门禁形同虚设。
> **PDV 与 TG4 的区别**TG4 在开发阶段用 API Mock 验证前端逻辑PDV 在部署后用真实环境验证功能可达性。详见 `SKILL.md` §PDV 章节。
> **与 req-test-gate 的关系**:本文档定义 E2E 测试的**执行技术**(怎么写 mock、怎么跑。质量门禁流程Gates 0-5、scope 分级、文档持久化)定义在 `req-test-gate` 技能中。
---

View File

@@ -0,0 +1,127 @@
# Go 集成测试模板
## 适用场景
当 git diff 显示同一功能的 **handlers/ + middleware/ + routes/** 文件均有变更时,除单元测试外应额外生成集成测试。
适用于:
- 多步骤 API 流程(登录→操作→验证→退出)
- 中间件拦截验证(权限、限流、模拟状态限制)
- 租户隔离 / 数据隔离验证
- 跨模块交互handler ↔ middleware ↔ repository
## 检测规则
通过命名模式识别同一功能的跨文件变更:
```
handlers/{feature}_handler.go
middleware/{feature}_middleware.go
routes/{feature}_routes.go
```
例如 `impersonation_handler.go` + `impersonation_middleware.go` + `impersonation_routes.go` 同时变更 → 生成 `tests/impersonation_integration_test.go`
## 生成规则
1. 测试文件放在 `backend/tests/` 目录(与 `test_helpers.go` 同包)
2. 使用 `SetupTestApp` + `defer TeardownTestApp` 初始化真实路由和数据库
3. 每个测试完全自包含:独立创建/清理数据
4. 异步持久化操作goroutine 写 DB`time.Sleep(200-500ms)` 后再验证
## 代码骨架
```go
package tests
import (
"encoding/json"
"fmt"
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFeature_Scenario(t *testing.T) {
testApp := SetupTestApp(t)
defer TeardownTestApp(t, testApp)
// === Setup: 创建测试数据 ===
// 使用 test_helpers.go 中的 helper 函数
sysAdmin := CreateTestSystemUser(t, testApp, "admin_scenario")
// tenantID := CreateTestTenant(t, testApp, "scenario_tenant")
// enterprise := CreateTestEnterpriseWithTenant(t, testApp, "Corp", "CODE", tenantID)
// tenantAdmin := CreateTestTenantAdmin(t, testApp, "tadmin", enterprise.ID, tenantID)
// === Cleanup: 按外键约束顺序清理 ===
defer CleanupImpersonationTestData(t, testApp,
[]int{sysAdmin.ID},
[]int{}, // enterpriseIDs
[]int64{}, // tenantIDs
)
// === 状态变量:跨步骤传递 ===
var token string
t.Run("Step1_InitialAction", func(t *testing.T) {
w := MakeAuthenticatedRequest(t, testApp, http.MethodPost,
"/api/v1/...",
map[string]string{"key": "value"},
sysAdmin,
)
require.Equal(t, http.StatusOK, w.Code, "Step1 failed: %s", w.Body.String())
var resp map[string]interface{}
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
// 提取后续步骤需要的数据
token = resp["data"].(map[string]interface{})["token"].(string)
})
t.Run("Step2_VerifyState", func(t *testing.T) {
if token == "" {
t.Skip("Step1 failed")
}
// 使用 Step1 产出的 token 继续验证
})
t.Run("StepN_AsyncVerification", func(t *testing.T) {
// 异步写入的数据需要等待
time.Sleep(300 * time.Millisecond)
// 然后验证 DB 数据
})
}
```
## 4 种必测场景
| 场景类型 | 说明 | 示例 |
|----------|------|------|
| **Happy Path** | 完整正常流程 | 开始模拟 → 访问 API → 查状态 → 退出 → 确认恢复 |
| **权限拒绝** | 无权限用户尝试操作 | 普通用户尝试模拟 → 403 |
| **隔离验证** | 跨租户/跨企业数据隔离 | tenant2 admin 访问 tenant1 企业 → 403 |
| **边界条件** | 输入校验、状态冲突 | 原因太短 → 400已在模拟中再次模拟 → 403 |
## Helper 函数参考
```go
// 来自 test_helpers.go
SetupTestApp(t) // 初始化完整应用(路由 + DB
CreateTestSystemUser(t, app, username) // 系统管理员 + JWT
CreateTestTenant(t, app, name) // 创建租户,返回 int64 ID
CreateTestEnterpriseWithTenant(t, app, name, code, tenantID) // 带租户的企业
CreateTestTenantAdmin(t, app, username, enterpriseID, tenantID...) // 租户管理员
CreateTestEnterpriseUser(t, app, username, enterpriseID) // 普通企业用户
ExtractImpersonationToken(t, response) // 从模拟响应提取 token
MakeAuthenticatedRequest(t, app, method, path, body, user) // 发送认证请求
CleanupImpersonationTestData(t, app, userIDs, enterpriseIDs, tenantIDs) // 按FK顺序清理
```
## 注意事项
- **Token 链式传递**:模拟 API 返回新 token后续请求必须用新 token
- **异步持久化**handler 用 goroutine 写 session/audit测试需 Sleep 后再查
- **数据隔离**:每个测试用唯一的 username/code避免测试间干扰
- **清理顺序**:外键约束要求先删子表再删父表

View File

@@ -0,0 +1,147 @@
# PDV Smoke Spec 模板
部署后验收 (Post-Deploy Verification) Playwright 测试模板。AI 根据需求变更范围,基于此模板动态生成验收 spec。
## 使用方式
```bash
# 指定部署环境 URL 执行
E2E_BASE_URL=https://staging.example.com npx playwright test e2e/pdv/ --project=chromium
```
## Spec 模板结构
```typescript
import { test, expect } from '@playwright/test';
const BASE_URL = process.env.E2E_BASE_URL || 'http://localhost:3000';
test.describe('PDV: {需求标题}', () => {
test.beforeEach(async ({ page }) => {
// 方式 1: 使用 storageState推荐需预先保存登录状态
// test.use({ storageState: 'e2e/.auth/user.json' });
// 方式 2: 手动登录
await page.goto(`${BASE_URL}/login`);
await page.fill('input[name="username"]', '{测试账号}');
await page.fill('input[name="password"]', '{测试密码}');
await page.click('button[type="submit"]');
await page.waitForURL('**/dashboard/**');
});
test('菜单可见性: {菜单名}', async ({ page }) => {
await page.goto(`${BASE_URL}/`);
await page.waitForSelector('.ant-menu');
// 检查侧栏包含新菜单项
const menu = page.locator('.ant-menu');
await expect(menu).toContainText('{菜单名}');
// 截图证据
await page.screenshot({ path: 'e2e-results/pdv-menu-{菜单名}.png', fullPage: false });
});
test('页面可达: {页面路由}', async ({ page }) => {
const response = await page.goto(`${BASE_URL}{页面路由}`);
// 验证 HTTP 状态
expect(response?.status()).toBeLessThan(400);
// 验证非白屏 — title 不含错误关键词
await expect(page).not.toHaveTitle(/error|500|404|not found/i);
// 验证页面有核心内容(非空白)
await expect(page.locator('{核心选择器}')).toBeVisible({ timeout: 10000 });
// 检查无 JS 报错(通过 console error 监听)
const errors: string[] = [];
page.on('console', msg => {
if (msg.type() === 'error') errors.push(msg.text());
});
await page.waitForTimeout(2000);
expect(errors.filter(e => !e.includes('favicon'))).toHaveLength(0);
// 截图证据
await page.screenshot({ path: 'e2e-results/pdv-page-{页面名}.png', fullPage: true });
});
test('API 连通: {接口描述}', async ({ request }) => {
// 需要带认证 token 调用
const resp = await request.get(`${BASE_URL}/api/v1/{路径}`, {
headers: {
'Authorization': 'Bearer {token}',
},
});
// 验证非 5xx 错误
expect(resp.status()).toBeLessThan(500);
// 可选:验证响应结构
// const body = await resp.json();
// expect(body).toHaveProperty('data');
});
});
```
## 占位符说明
| 占位符 | 含义 | 来源 |
|--------|------|------|
| `{需求标题}` | 需求名称 | `ai-proj req get --id <id>` |
| `{菜单名}` | 新增的菜单文本 | 从需求关联的前端任务中提取 |
| `{页面路由}` | 新增/变更的前端路由 | 从前端路由配置或 PRD 提取 |
| `{核心选择器}` | 页面核心内容的 CSS 选择器 | 如 `h1`, `.page-title`, `[data-testid="xxx"]` |
| `{测试账号}` / `{测试密码}` | 测试环境登录凭据 | 环境配置 |
| `{token}` | API 认证 token | 登录后获取 |
| `{接口描述}` / `{路径}` | 关键 API 端点 | 从后端路由或 PRD 提取 |
| `{页面名}` | 截图文件名标识 | 自定义 |
## 生成示例OKR 功能)
```typescript
import { test, expect } from '@playwright/test';
const BASE_URL = process.env.E2E_BASE_URL || 'http://localhost:3000';
test.describe('PDV: OKR 团队/对齐/设置/评分功能', () => {
test.beforeEach(async ({ page }) => {
await page.goto(`${BASE_URL}/login`);
await page.fill('input[name="username"]', 'testuser');
await page.fill('input[name="password"]', 'TestPass123');
await page.click('button[type="submit"]');
await page.waitForURL('**/dashboard/**');
});
test('菜单可见性: OKR', async ({ page }) => {
await page.goto(`${BASE_URL}/`);
await page.waitForSelector('.ant-menu');
await expect(page.locator('.ant-menu')).toContainText('OKR');
await page.screenshot({ path: 'e2e-results/pdv-menu-okr.png' });
});
test('页面可达: /okr/my', async ({ page }) => {
const response = await page.goto(`${BASE_URL}/okr/my`);
expect(response?.status()).toBeLessThan(400);
await expect(page).not.toHaveTitle(/error|500|404/i);
await expect(page.locator('h1, .page-title')).toBeVisible({ timeout: 10000 });
await page.screenshot({ path: 'e2e-results/pdv-page-okr-my.png', fullPage: true });
});
test('页面可达: /okr/team', async ({ page }) => {
const response = await page.goto(`${BASE_URL}/okr/team`);
expect(response?.status()).toBeLessThan(400);
await expect(page).not.toHaveTitle(/error|500|404/i);
await expect(page.locator('h1, .page-title')).toBeVisible({ timeout: 10000 });
await page.screenshot({ path: 'e2e-results/pdv-page-okr-team.png', fullPage: true });
});
test('API 连通: OKR objectives', async ({ request }) => {
const resp = await request.get(`${BASE_URL}/api/v1/okr/objectives`);
expect(resp.status()).toBeLessThan(500);
});
});
```

View File

@@ -0,0 +1,8 @@
{
"name": "review-checklist-plugin",
"description": "项目级代码评审检查清单。按项目积累的特定检查项,挂载在 dev-review 下自动加载。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,42 @@
# AI-Proj 代码评审检查清单
## 后端Go + Gin + GORM
### 分层架构
- [ ] Handler 是否直接 import `database/` 包?— 禁止,必须通过 Service 层。教训:架构退化导致循环依赖
- [ ] 新 Handler 是否在 routes/ 中注册?— 遗漏会导致 404
- [ ] MCP 专用 endpoint 是否包含 `/mcp/` 前缀?— 教训:缺少前缀导致 MCP bridge 404
### 数据库
- [ ] 新增 Migration 文件名是否符合 `YYYYMMDDHHMMSS_xxx.up.sql` 格式?
- [ ] Migration 是否有对应的 `.down.sql`
- [ ] GORM 查询是否带 `tenant_id` 过滤?(多租户安全)
- [ ] 软删除查询是否正确使用 `Unscoped()`?— 误用导致查不到已删除数据或查出已删除数据
### 认证与权限
- [ ] 新 API 是否配置了 Auth 中间件?— 遗漏导致未授权访问
- [ ] JWT token 类型是否区分 access/refresh— 教训token 混用导致安全漏洞
- [ ] bcrypt cost 是否使用 12— 教训:默认 cost 10 导致登录失败
### Redis
- [ ] Redis key 是否有 TTL— 缺少 TTL 导致内存泄露
- [ ] Redis 不可用时是否降级到数据库?
## 前端React 18 + Ant Design
### Modal 安全
- [ ] `Modal.success/info/warning/error` 之后是否有立即执行的 UI 操作?— 必须放在 `onOk` 回调中。教训:两个 Modal 同时弹出互相遮挡
### 状态管理
- [ ] React Query 的 queryKey 是否正确包含所有依赖参数?— 缺少导致缓存错误
- [ ] 列表页分页是否正确重置 page— 教训:筛选条件变更后 page 未重置导致空页
### 类型安全
- [ ] 是否有 `any` 类型?— 应使用具体类型
- [ ] API 响应是否有 TypeScript 接口定义?
## 通用
- [ ] `.env` <20><>凭据文件是否被意外加入 git
- [ ] 是否有硬编码的 URL/IP/端口?— 应使用配置
- [ ] 错误日志是否包含足够的上下文信息user_id, tenant_id, request_id

View File

@@ -0,0 +1,20 @@
# Coolbuy PaaS酷采3.0)代码评审检查清单
## 后端Go + Gin + MySQL
### 多租户
- [ ] 所有查询是否带 `tenant_id``enterprise_id` 过滤?
- [ ] 跨租户数据操作是否被阻止?
### 数据迁移
- [ ] 从酷采2.0迁移的字段映射是否正确varchar ID → bigint ID
- [ ] 迁移脚本是否处理了酷采2.0<EFBFBD><EFBFBD><EFBFBD>软删除标记is_delete → deleted_at
## 前端Vue 3 + Ant Design Vue
### i18n
- [ ] 新增文案是否使用 `$t()` 国际化?— 不允许硬编码中文
- [ ] i18n key 是否在 zh-CN 和 en-US 都有定义?
### 权限
- [ ] 按钮/菜单是否有权限控制v-permission 指令)?

View File

@@ -0,0 +1,23 @@
# 通用代码评审检查清单
适用于所有项目,补充五视角扫描法。
## API 设计
- [ ] RESTful 命名是否规范?(复数名词、无动词)
- [ ] 分页参数是否有默认值和上限?
- [ ] 响应格式是否统一code/message/data
## 错误处理
- [ ] 错误是否被正确传播?(不要吞掉错误)
- [ ] 用户可见的错误消息是否友好?(不暴露技术细节)
- [ ] 是否有 panic recover 兜底?
## 性能
- [ ] 列表查询是否有分页?(不允许无限制查询)
- [ ] N+1 查询问题?(循环内查数据库)
- [ ] 是否有不必要的全表扫描?(缺少索引)
## 可维护性
- [ ] 魔法数字是否提取为常量?
- [ ] 复杂业务逻辑是否有注释说明?
- [ ] 函数是否过长?(超过 100 行考虑拆分)

View File

@@ -0,0 +1,49 @@
---
name: review-checklist
description: 项目级代码评审检查清单。按项目积累特定检查项,挂载在 dev-review 下自动加载。每次 CR 时触发。
---
# 代码评审检查清单插件 (review-checklist)
## 概述
本插件为 `dev-review` 提供**项目特定的检查清单**,补充五视角扫描法之外的项目级经验。
检查清单按项目独立维护,每个项目文件记录该项目踩过的坑和必查项。
## 使用方式
1. `dev-review` 执行五视角扫描时,自动加载当前项目的检查清单
2. 扫描完成后,逐条检查清单项
3. 检查结果附加到 CR 报告的「项目检查清单」章节
## 检查清单文件
```
review-checklist-plugin/
├── skills/SKILL.md # 本文件
└── checklists/
├── ai-proj.md # AI-Proj 项目清单
├── coolbuy-paas.md # 酷采3.0 项目清单
└── general.md # 通用清单(所有项目适用)
```
## 如何添加检查项
当 CR 中发现了一个**项目特有**的问题模式,且未来可能复发时:
1. 打开对应项目的检查清单文件
2. 添加条目,格式:`- [ ] {检查项} — 教训:{来源}`
3. 标注严重度和适用范围
**不要添加**五视角扫描已覆盖的通用安全/并发/边界问题。
## CR 报告附加章节
```markdown
### 项目检查清单({项目名}
| # | 检查项 | 结果 | 说明 |
|---|--------|------|------|
| 1 | {检查项} | ✅/❌/N/A | {说明} |
```

View File

@@ -0,0 +1,8 @@
{
"name": "req-compare-plugin",
"description": "对比式需求分析插件。系统平移、竞品借鉴、版本升级时的参考对象对比分析。挂载在 analysis 阶段。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,210 @@
---
name: req-compare
description: 对比式需求分析插件。系统平移、竞品借鉴、版本升级时使用参考对象对比法编写 PRD。挂载在 analysis 阶段,需要对比分析时由 req-prd 推荐激活。
---
# 对比式需求分析插件 (req-compare)
## 概述
当进行**系统平移、功能迁移、竞品借鉴**时,使用对比分析法编写 PRD确保新系统功能完整且有所改进。
**触发条件**
- 用户提到"从 XX 系统迁移"、"参考 XX 功能"、"平移"、"借鉴"
- req-prd 检测到需求涉及参考系统
## 适用场景
| 场景 | 说明 | 示例 |
|------|------|------|
| 系统平移 | 旧系统迁移到新技术栈 | 酷采2.0 → 酷采3.0 |
| 功能借鉴 | 参考竞品功能设计 | 参考飞书设计协作功能 |
| 版本升级 | 基于当前版本优化 | V1.0 → V2.0 重构 |
---
## 对比分析工作流
```
1. 确定参考对象
├── 识别参考系统(可以是多个)
├── 获取访问权限(测试环境、源代码)
└── 明确对比目标
2. 参考对象分析
├── 功能调研(前端页面操作)
├── 业务数据分析(核心实体、字段含义)
├── 业务逻辑分析(规则、流转、校验)
└── 用户体验分析
3. 对比分析
├── 功能对比表(保留/优化/新增/废弃)
├── 业务数据对比(实体映射、新增数据项)
├── 用户体验对比
└── 非功能需求对比(性能、安全)
4. PRD 编写
├── 背景说明(明确参考来源)
├── 功能需求(标注来源与变更)
├── 业务数据需求(实体、字段、规则)
└── 非功能需求(性能、安全、兼容性)
```
---
## 对比式 PRD 模板
```markdown
# [功能模块名称] PRD
## 1. 文档概述
### 1.1 文档信息
| 项目 | 内容 |
|------|------|
| 文档名称 | [模块名称] 需求文档 |
| 版本 | V1.0 |
| 创建日期 | [日期] |
| **需求来源** | **[参考系统名称] 平移/借鉴** |
| **参考系统** | **[参考系统访问地址]** |
### 1.2 背景说明
本需求文档基于 **[参考系统]** 的 [模块名称] 功能分析,将其平移至 [目标系统]。
**参考系统信息**
- 系统地址:[URL]
- 技术栈:[技术栈描述]
- 源码位置:[源码路径](如有)
---
## 2. 参考系统分析
### 2.1 功能截图
[插入参考系统功能截图]
### 2.2 业务数据(参考系统)
| 数据实体 | 核心字段 | 业务含义 |
|----------|----------|----------|
| [实体名] | [字段列表] | [业务说明] |
### 2.3 核心功能(参考系统)
| 功能 | 用户操作 | 业务规则 |
|------|----------|----------|
| [功能名] | [操作描述] | [规则说明] |
### 2.4 业务逻辑(参考系统)
- 核心业务规则摘要
- 数据校验规则
- 状态流转逻辑
---
## 3. 功能对比分析
### 3.1 功能对比表
| 序号 | 功能 | 参考系统 | 目标系统 | 变更类型 | 说明 |
|------|------|----------|----------|----------|------|
| 1 | [功能1] | ✅ | ✅ | 保留 | 直接平移 |
| 2 | [功能2] | ✅ | ✅+ | 优化 | [优化内容] |
| 3 | [功能3] | ❌ | ✅ | 新增 | [新增原因] |
| 4 | [功能4] | ✅ | ❌ | 废弃 | [废弃原因] |
### 3.2 业务数据对比
| 数据项 | 参考系统 | 目标系统 | 变更 | 说明 |
|--------|----------|----------|------|------|
| [数据项] | [描述] | [描述] | 保留/优化/新增/废弃 | [说明] |
### 3.3 非功能需求对比
| 维度 | 参考系统 | 目标系统要求 |
|------|----------|-------------|
| 性能 | [现状] | [目标] |
| 安全 | [现状] | [目标] |
| 用户体验 | [现状] | [目标] |
---
## 4. 目标系统设计
### 4.1 功能清单
| 序号 | 功能 | 优先级 | 来源 | 说明 |
|------|------|--------|------|------|
| 1 | [功能] | P0 | 平移 | 从参考系统平移 |
### 4.2 业务数据需求(目标系统)
| 数据实体 | 核心字段 | 业务规则 | 来源 |
|----------|----------|----------|------|
| [实体名] | [字段列表] | [校验/约束] | 平移/新增 |
### 4.3 业务规则
- [ ] 规则1沿用参考系统
- [ ] 规则2优化调整
---
## 5. 上线优先级
1. [P0 功能] — 核心路径
2. [P1 功能] — 重要但可后续迭代
3. [P2 功能] — 优化项
## 6. 注意事项
- 参考系统中 [xxx] 逻辑需要特别注意
- 新系统中需改进 [xxx] 问题
```
---
## 参考对象分析方法
### 1. 前端功能调研
- 访问参考系统,截图记录页面布局和交互流程
- 记录用户操作路径CRUD、搜索、筛选等
- 标注交互细节(表单校验、提示信息、异常处理)
### 2. 业务逻辑调研
- 梳理核心业务规则和状态流转
- 记录数据校验规则
- 标注业务异常处理方式
> **技术层分析**代码结构、数据库表结构、API 接口)请在 design 阶段使用 `req-design` 技能完成。
---
## 竞品分析模板
```markdown
# [竞品名称] 分析
## 1. 产品概述
- 定位:
- 核心功能:
- 目标用户:
## 2. 功能对比
| 功能 | 我们 | 竞品A | 竞品B |
|------|------|-------|-------|
| 功能1 | ✅/❌/部分 | ... | ... |
## 3. 优劣势分析
### 优势
1. ...
### 劣势
1. ...
## 4. 可借鉴点
- ...
## 5. 差异化策略
- ...
```
---
## 最佳实践
1. **先调研再写 PRD** — 充分理解参考系统后再动笔
2. **功能对比表必填** — 明确每个功能的保留/优化/新增/废弃决策
3. **标注来源** — 每个功能需求标注是"平移"还是"新增"
4. **记录废弃原因** — 参考系统有但不做的功能,必须记录原因
5. **不抄技术实现** — 对比的是业务功能,不是代码结构

View File

@@ -0,0 +1,8 @@
{
"name": "req-design-plugin",
"description": "需求开发设计技能。PRD 到开发设计的转换API 契约、数据模型变更、任务拆分、风险评估。",
"version": "2.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,476 @@
---
name: req-design
description: 需求开发设计技能。用于 PRD 到开发设计的转换API 契约定义、数据模型变更方案、变更文件清单、开发任务拆分、技术风险评估。当用户执行 /req doc 或需要编写开发设计文档时自动激活。
arguments: <REQ-ID>
---
# 需求开发设计 Skill (req-design)
## 概述
本技能用于将 PRD 文档转换为**开发设计文档**是产品需求req-prd和编码实现dev-coding之间的桥梁。
**核心输出**
- API 契约定义(前后端对齐)
- 数据模型变更方案(新增/修改表和字段)
- 变更文件清单(标注层级和改动类型)
- 开发任务拆分SMART 原则2-4h 粒度)
- 技术风险评估
**不包含**(由其他技能负责):
- 具体代码实现 → `dev-coding`
- 代码规范和编码模式 → `dev-coding`
- 深度架构设计 → `dev-arch`(插件)
- 数据库迁移细节 → `db-migration`(插件)
---
## 技能间契约
| 上游 | 本技能输入 | 本技能输出 | 下游 |
|------|-----------|-----------|------|
| req-prd | PRD 文档(用户故事、业务规则、验收标准) | 开发设计文档 | dev-coding |
**输出格式要求**
- API 契约B 级格式(见下方标准)
- 变更清单:按文件列出,标注层级和改动类型
- 任务拆分:每任务 2-4hSMART 原则
---
## 工作流程
```
0. ⚠️ 需求验证防浪费5-10 分钟)
├── 现有 UI 检查:功能是否已存在?
├── 数据检查:字段/API 是否已有?
└── 价值验证:痛点明确?有更简方案?
1. 获取需求信息
├── mcp__ai-proj__get_requirement
└── mcp__ai-proj__get_requirement_tasks找 PRD 任务)
2. 分析 PRD 文档
├── 提取功能点和业务规则
├── 识别数据实体和关系
└── 确定非功能需求(性能、安全)
3. 探索代码库
├── 搜索相关现有代码Grep/Glob/Explore
├── 识别修改文件和可复用代码
└── 分析依赖关系
4. 设计 API 契约
├── 定义新增/修改接口B 级格式)
├── 定义请求/响应结构
└── 定义错误码
5. 设计数据模型变更
├── 新增/修改表和字段
├── 索引设计
└── 数据迁移方案(如需要)
6. 生成变更文件清单
├── 后端Model → Repository → Service → Handler → Route → Migration
├── 前端Types → Services → Components → Pages
└── 标注每个文件的改动类型(新增/修改/删除)
7. 拆分开发任务
├── 按模块/文件拆分子任务
└── mcp__ai-proj__create_subtask
8. 技术风险评估
├── 影响分析(兼容性、性能)
└── 回退方案
```
---
## 需求验证(第 0 步)
> **教训**:不先验证需求,可能花几小时实现冗余功能。
**验证清单**5-10 分钟):
1. **现有功能检查**(最重要)
- 打开相关页面,目视检查功能是否已存在
- 检查数据库是否已有相关字段
- 检查 API 是否已返回所需数据
2. **价值验证**
- 解决什么具体痛点?
- 有无更简单的替代方案?
- 投入产出比是否合理?
3. **设计审查**
- UI 设计是否合理?不重复、不混乱?
- 是否符合现有设计规范?
**通过验证后再开始设计!**
---
## API 契约格式标准B 级)
所有新增/修改 API 必须使用以下格式定义契约,作为前后端对齐的桥梁:
```
### POST /api/v1/enterprises
描述: 创建企业
请求体:
- name: string (required) — 企业名称,最长 100 字符
- code: string (required) — 企业编码,唯一,正则 ^[A-Z0-9-]+$
- contact_email: string (optional) — 联系邮箱
响应 200:
- id: int
- name: string
- code: string
- created_at: datetime
错误:
- 400: 参数校验失败name/code 为空或格式错误)
- 409: 编码已存在
- 403: 无权限创建企业
```
**B 级规则**
- 列出所有字段、类型、必填/可选
- 标注校验规则(长度、格式、唯一性)
- 列出所有可能的错误码和含义
- 不需要 JSON 示例A 级才需要)
---
## 开发设计文档模板
```markdown
# [需求标题] 开发设计文档
## 1. 需求概述
### 1.1 需求信息
| 项目 | 内容 |
|------|------|
| 需求编号 | REQ-YYYYMMDD-XXXX |
| 需求标题 | [标题] |
| 优先级 | high/medium/low |
| 预估工时 | Xh |
### 1.2 功能点清单
- [ ] 功能点1[描述]
- [ ] 功能点2[描述]
---
## 2. 代码库分析
### 2.1 相关现有代码
| 文件路径 | 层级 | 当前功能 | 改动类型 |
|---------|------|----------|---------|
| `backend/models/xxx.go` | Model | 数据模型 | 新增字段 |
| `backend/services/xxx_service.go` | Service | 业务逻辑 | 新增方法 |
### 2.2 可复用代码
- [描述已有的可参考实现]
### 2.3 依赖关系
- [需要注意的调用链和依赖]
---
## 3. API 契约
### 3.1 新增接口
### POST /api/v1/xxx
描述: [功能描述]
请求体:
- field1: type (required) — 说明
- field2: type (optional) — 说明
响应 200:
- field1: type
- field2: type
错误:
- 400: [说明]
- 404: [说明]
### 3.2 修改接口
[列出需要修改的现有接口及变更内容]
---
## 4. 数据模型变更
### 4.1 新增表
| 表名 | 说明 |
|------|------|
| xxx | [用途] |
**字段设计**
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| id | BIGSERIAL | PK | 主键 |
| tenant_id | BIGINT | NOT NULL, INDEX | 租户ID |
| name | VARCHAR(255) | NOT NULL | 名称 |
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 |
**索引**
| 索引名 | 字段 | 类型 | 说明 |
|--------|------|------|------|
| idx_xxx_tenant | tenant_id | B-tree | 租户查询 |
### 4.2 修改表
| 表名 | 变更 | 说明 |
|------|------|------|
| xxx | 新增字段 yyy | [用途] |
### 4.3 数据迁移(如需要)
[迁移方案描述]
---
## 5. 变更文件清单
### 后端
| 文件 | 层级 | 改动类型 | 改动说明 |
|------|------|---------|---------|
| `models/xxx.go` | Model | 修改 | 新增字段 |
| `database/xxx_repository.go` | Repository | 修改 | 新增查询方法 |
| `services/xxx_service.go` | Service | 修改 | 新增业务方法 |
| `handlers/xxx_handler.go` | Handler | 修改 | 新增接口 |
| `routes/xxx_routes.go` | Route | 修改 | 注册新路由 |
| `migrations/YYYYMMDD_xxx.up.sql` | Migration | 新增 | 表结构变更 |
### 前端
| 文件 | 层级 | 改动类型 | 改动说明 |
|------|------|---------|---------|
| `types/xxx.ts` | Types | 修改 | 新增接口定义 |
| `services/xxxService.ts` | Service | 修改 | 新增 API 调用 |
| `pages/XxxPage.tsx` | Page | 修改 | 新增功能 UI |
---
## 6. 开发任务拆分
### 6.1 任务列表
| # | 任务标题 | 预估工时 | 依赖 |
|---|---------|---------|------|
| 1 | [后端] Model + Migration | 1h | - |
| 2 | [后端] Repository + Service | 2h | #1 |
| 3 | [后端] Handler + Route | 2h | #2 |
| 4 | [前端] Types + Service | 1h | #3 |
| 5 | [前端] 页面开发 | 3h | #4 |
| 6 | [测试] 单元测试 | 2h | #3, #5 |
### 6.2 实施顺序
[按依赖关系排列的开发步骤]
---
## 7. 技术风险评估
### 7.1 影响分析
| 改动类型 | 影响范围 | 风险等级 | 应对措施 |
|---------|---------|---------|---------|
| [描述] | [范围] | 高/中/低 | [措施] |
### 7.2 风险清单
- [ ] 数据库:是否需要数据迁移?是否影响数据完整性?
- [ ] API是否破坏兼容性是否需要版本管理
- [ ] 前端:是否影响现有页面?是否有性能瓶颈?
- [ ] 业务:是否影响核心流程?是否需要灰度?
### 7.3 回退方案
[如果上线出问题,如何回退]
---
## 8. 注意事项
[特殊说明、边界情况、兼容性要求]
```
---
## 任务拆分规则
### SMART 原则
- **Specific**(具体):明确要修改哪个文件/模块
- **Measurable**(可衡量):清晰的完成标准
- **Achievable**(可实现):单个任务 2-4 小时完成
- **Relevant**(相关):与需求直接相关
- **Time-bound**(有时限):预估工时
### 拆分粒度
- ✅ 好的粒度:`[Handler] 修改 manual_handler.go 添加发布接口2h`
- ❌ 太粗:`[后端] 实现所有后端功能`
- ❌ 太细:`[Handler] 添加 import 语句`
### 按文件拆分(推荐)
- 每个文件对应一个子任务
- 格式:`[层级] 修改 文件名 简要说明`
### 按功能模块拆分(大改动)
- 将相关文件归为一个模块
- 格式:`[模块] 功能描述`
### 标准开发顺序
```
第一阶段:数据层
├── Model 层:定义数据结构
├── Migration创建/修改表
└── Repository 层:实现数据访问
第二阶段:业务层
├── Service 层:实现业务逻辑
└── 编写单元测试
第三阶段:接口层
├── Handler 层:实现 HTTP 接口
├── Route 层:注册路由
└── API 文档Swagger
第四阶段:前端层
├── Types定义 TypeScript 接口
├── Services封装 API 调用
├── Components开发可复用组件
└── Pages实现业务页面
第五阶段:测试与优化
├── 后端单元测试
├── 前端组件测试
└── E2E 测试
```
---
## 技术风险评估框架
### 影响分析矩阵
| 改动类型 | 影响范围 | 风险等级 | 应对措施 |
|---------|---------|---------|---------|
| 新增字段(非必填) | 低 | 低 | 添加 Migration向后兼容 |
| 修改字段类型 | 中 | 中 | 数据迁移脚本,充分测试 |
| 删除字段 | 高 | 高 | 确认无依赖,先标记废弃 |
| 新增 API 接口 | 低 | 低 | 接口设计评审 |
| 修改 API 接口 | 中 | 中 | 保留旧接口,添加版本号 |
| 删除 API 接口 | 高 | 高 | 确认无调用,发布公告 |
| 新增前端页面 | 低 | 低 | 路由冲突检查 |
| 修改核心组件 | 高 | 高 | 充分测试所有使用场景 |
### 性能影响评估
| 维度 | 评估项 |
|------|--------|
| 数据库 | 查询复杂度、索引使用、数据量、并发影响 |
| API | 响应时间预期、QPS 预估、缓存策略、限流需求 |
| 前端 | 首屏加载影响、渲染性能、内存占用 |
---
## 与 ai-proj 集成
### 文档创建
```typescript
// 创建开发设计文档并关联任务
mcp__ai-proj__create-and-attach({
taskId: <设计任务ID>,
title: "开发设计文档 - [需求标题]",
content: "<使用上方模板生成的内容>"
})
```
### 子任务拆分
```typescript
mcp__ai-proj__create_subtask({
parentId: <开发任务ID>,
title: "[Handler] 修改 manual_handler.go 添加发布接口"
})
```
### 进度更新
```typescript
mcp__ai-proj__update_task_document({
taskId: <设计任务ID>,
content: "<更新后的设计文档>"
})
```
---
## 插件触发
| 插件 | 触发条件 | 说明 |
|------|---------|------|
| `dev-arch` | 新模块/新表/复杂架构 | 深度架构设计 |
| `db-migration` | 涉及数据库变更 | 数据库迁移方案 |
当检测到以上条件时,建议用户启用对应插件。
---
## 最佳实践
1. **先验证再设计** — 5 分钟验证省 3 小时返工
2. **API 契约先行** — 前后端对齐的桥梁,先定义再实现
3. **复用优于新建** — 充分探索代码库,识别可复用代码
4. **风险前置** — 在设计阶段识别风险,而非编码时才发现
5. **粒度适中** — 任务拆分 2-4h不要太粗也不要太细
6. **文档可操作** — 开发者可直接按设计文档实施
---
## 常见问题
### Q1: 如何确定是否需要新增数据库表?
检查:新数据是否与现有实体有独立生命周期?是否需要独立查询?是否 1:N 或 N:N 关系?任一满足则新增表。
### Q2: 什么时候需要创建子任务?
修改 3 个以上文件 / 预估工时 > 4h / 涉及多个层级 → 创建子任务。
### Q3: API 契约需要多详细?
B 级:字段 + 类型 + 必填/可选 + 校验规则 + 错误码。不需要 JSON 示例。
### Q4: 设计文档和 PRD 的边界?
PRD 说「做什么」用户故事、业务规则、验收标准设计文档说「怎么做」API、数据模型、文件清单
---
## Memory 隔离规则(强制,源自 devflow-claude 借鉴)
**规则:本 skill 产出的设计文档禁止受 auto-memory 影响结构和字段定义。**
### 禁止行为
1. 不得用 memory 里的历史 API 契约填充当前设计(避免张冠李戴)
2. 不得根据 memory 偏好省略"变更文件清单"/"数据模型变更"等章节
3. 不得读取 `~/.claude/projects/*/memory/` 生成 API 字段或 SQL
### 允许行为
- memory 可影响交互风格、命令推荐
- memory 可记住"用户偏好 RESTful 而非 RPC" 这类**偏好**,但字段定义必须基于当前需求
### Why
设计文档是开发契约,字段/接口/表结构错一个字就是 bug。memory 污染会让 AI 脑补出"看起来像但不对"的字段。必须严格基于当前 PRD + 代码现状生成。
**参考**devflow-claude `plugins/req/commands/_common.md` 同名规则。
---
## 变更记录
| 版本 | 日期 | 变更内容 |
|------|------|----------|
| V1.0 | 2026-01-26 | 初始版本(原名 req-dev |
| V2.0 | 2026-04-06 | 重构为 req-design移除架构指南和编码规范聚焦 API 契约 + 任务拆分 |
| V2.1 | 2026-04-16 | 新增 Memory 隔离规则REQ-20260416-0017 |

View File

@@ -1,7 +1,8 @@
{
"name": "req-dev-plugin",
"description": "Plugin for req-dev",
"description": "[已废弃] 请使用 req-design-plugin。需求开发设计功能已迁移。",
"version": "1.0.0",
"deprecated": true,
"author": {
"name": "qiudl"
}

View File

@@ -47,6 +47,7 @@ analysis → design → dev → review → testing → [待部署池] → releas
- **操作前先确认实际 ID** — 从 URL 提取 ID`/requirements/897` → ID=897
- **务实路线关闭也必须补全关联任务** — 每个进度条阶段需创建关联任务
- **阶段内容门禁(防空转)** — `/req next` 时检查关键阶段任务是否有实质内容
- **Harness 环境检测** — `/req dev` 启动开发前,快速检测项目基础设施(`.husky/` 存在?`scripts/check-*.sh` 存在。若两者都不存在Level 0输出一行提示「项目无质量护栏建议先运行 `/harness init`」。检测结果不阻塞开发,仅提示
## 禁止直接调用(必须走命令流程)
@@ -86,27 +87,45 @@ Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD
1. /req new → 创建需求 (draft)
2. 需求讨论 → 输出结论摘要,用户确认
3. req-prd 技能 → 编写 PRD创建【评审】PRD 任务)
3.5 /req prototype → 生成 Stitch 原型(可选,有 UI 时推荐)
4. /req submit → 提交评审 (pending),含 4 道门禁
5. /req review pass → 评审通过 (approved, delivery_stage=analysis)
6. /req next → 推进到 design/dev 阶段
7. /req dev → 启动开发(创建【开发】任务, delivery_stage=dev
8. /req next推进到 review 阶段
9. /req cr → 代码评审(创建【代码评审】任务
7.5 /req ci CI 质量门禁检查与自动修复PR 提交后执行)
8. /req next → 推进到 review需 quality_gate 证据
9. /req cr → 代码评审 + 约定检查 + bug约定建议⭐ harness 自动)
10. /req next → 推进到 testing 阶段
11. /req test → 测试验收(5-Gate 流程
12. /req deploy → 批量部署(DG1-DG6 Deploy Gates
11. /req test → 测试验收Gate 0B 约定检查 ⭐ + Gate 1-5
12. /req deploy → 批量部署(build-and-push.sh → Jenkins ai-proj
13. /req done → 归档 (archived) + git commit + push
```
> ⭐ 标记的步骤是 Harness Engineering 自动嵌入的,无需手动调用。
**5 阶段文档**
| 阶段 | 文档名 | 技能 |
|------|--------|------|
| PRD | 01-PRD.md | `req-prd` |
| 测试 | 02-测试报告.md | 自动生成 |
| 发布 | 03-发布记录.md | 自动生成 |
| 发布 | 03-发布记录.md | 自动生成(含 PDV 验收章节) |
| 归档 | 04-生命周期总结.md | 自动生成 |
**03-发布记录.md 中 PDV 章节模板**
```markdown
### 部署后验收 (PDV)
| 检查项 | 结果 | 截图 |
|--------|------|------|
| 页面可达: /path/to/page | ✅ PASS | [截图] |
| 菜单可见: {菜单名} | ✅ PASS | [截图] |
| 基础渲染: 无白屏/JS 报错 | ✅ PASS | [截图] |
| API: /api/v1/{路径} | ✅ PASS | — |
PDV 结论: ✅ 全部通过 / ❌ {N}项失败,阻断推进
```
## 任务命名规范
| linkRole | 前缀 | 示例 |
@@ -117,6 +136,7 @@ Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD
| code_review | 【代码评审】 | 【代码评审】CR: 代码审查 |
| test | 【测试】 | 【测试】集成测试验证 |
| deploy | 【部署】 | 【部署】部署到 staging |
| verification | 【验收】 | 【验收】PDV: OKR 功能部署验收 |
| documentation | 【文档】 | 【文档】API 文档更新 |
## 阶段内容门禁(防空转)
@@ -131,6 +151,24 @@ Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD
未通过 → AskUserQuestion补充文档 or 强制跳过+记录原因)
### 部署门禁(推进到 released 前)
`/req deploy` 推进 `released` 前,必须通过 3 道门禁:
```
Deploy Gate 1: 健康检查 ── /health 返回 200服务存活
Deploy Gate 2: PDV 验收 ── linkRole=verification 的【验收】任务存在且 completed
Deploy Gate 3: 证据完整 ── 验收任务有文档,含检查项表格 + E2E 截图 + 通过/失败结论
```
**PDV 验收任务生命周期**
1. `/req deploy` 步骤 6 自动创建:`ai-proj task create --title "【验收】PDV: {需求标题}"`
2. 关联需求:`ai-proj req link --id <req_id> --task-ids <task_id> --link-role verification`
3. 执行 Playwright PDV 冒烟测试
4. 附加验收文档(检查项表格 + 截图证据 + 结论):`ai-proj task append-doc --id <task_id>`
5. **全部通过**`ai-proj task complete --id <task_id>` → 门禁放行
6. **任一失败** → 任务保持 in_progress阻断推进报告失败项
### CR 五视角扫描法
**核心原则**:实现阶段关注"怎么让它跑通",评审阶段关注"怎么让它出错"。AI 必须**切换到对抗性思维**,逐一用以下 5 个视角扫描代码。
@@ -231,6 +269,18 @@ Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD
**`/req split [REQ-ID]`** — 拆分为开发任务(后端/前端/测试)并关联
### 原型设计
**`/req prototype [REQ-ID]`** — 基于 PRD 生成 Stitch 原型:
1. 读取 PRD 文档,提取 UI 相关描述
2. 创建 Stitch 项目 + 生成页面(调用 req-prototype 子技能)
3. 截图回填 PRD「4.2 界面原型」章节
- 参数:`--device [desktop|mobile|tablet]``--model [pro|flash]`
**`/req prototype edit [REQ-ID] --prompt "..."`** — 修改已有原型
**`/req prototype variant [REQ-ID]`** — 生成设计变体供选择
### 提交评审
**`/req submit [REQ-ID]`** ⭐ — 从 draft 到 pending 的唯一合法路径:
@@ -258,6 +308,10 @@ Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD
5. 自动创建目标阶段建议任务
6. 展示:「✅ 已创建: #XXXX {任务名}。如需撤销请说明」
**dev → review 门禁**
- `pr_created`: PR 已创建
- `quality_gate`: CI 质量门禁通过记录质量门禁未通过时提示「CI 质量门禁未通过,请先运行 `/req ci`」)
**阶段顺序**`analysis → design → dev → review → testing → [待部署池] → released`
**`/req resume [REQ-ID]`** — 会话断点恢复:`ai-proj req get --id <id>` 获取 delivery_stage + 任务状态 + 建议操作
@@ -274,24 +328,73 @@ Gate 4: 完整性检查 ── 三段式完整 + 验收标准 ≥ 2 条 + PRD
2. `git diff` / `find` 确定变更范围(文件数、行数)
3. 读取所有变更文件源码(非 test 文件)
4. **五视角扫描**:逐一用攻击者/泄露者/并发者/边界者/依赖者视角审查
5. `ai-proj task create` 创建【代码评审】任务并关联需求linkRole=code_review
6. `ai-proj create-and-attach` 附加 CR 报告文档(必须含五视角扫描结果)
7. 展示发现摘要AskUserQuestion 确认是否创建 bug 修复任务
8. 若有 High/Critical 发现 → `ai-proj task create` 创建关联修复任务
5. **约定检查**:运行所有 `scripts/check-*.sh --ci`,将结果写入 CR 报告
6. **⭐ Bug 约定建议**bug 类需求自动触发category=bug或标题含 fix/修复/bug或描述含根因/复现步骤):
- 分析本次 bug 的根因模式
- 判断可检测性:能写 grep 找到同类问题?(规则见 convention-flow.md「可检测性判断」
- 不可检测 → 仅在 CR 报告记录根因,跳过
- 可检测 → 检查已有 `scripts/check-*.sh` 是否已覆盖 → 已覆盖则跳过
- 扫描代码库统计同类模式数量 N
- AskUserQuestionN=0: 防未来复发N>0: 防恶化+逐步清理)
- 是 → 执行 convention flow → 产出物**单独 commit**`chore: 建立 {name} 约定`
7. `ai-proj task create` 创建【代码评审】任务并关联需求linkRole=code_review
8. `ai-proj create-and-attach` 附加 CR 报告文档(必须含五视角扫描结果 + 约定检查结果)
9. 展示发现摘要AskUserQuestion 确认是否创建 bug 修复任务
10. 若有 High/Critical 发现 → `ai-proj task create` 创建关联修复任务
**`/req ci [REQ-ID]`** — CI 质量门禁检查与自动修复:
1. `check-ci-status.sh` 检查当前分支 CI 状态
- 通过 → 写入 `quality_gate` 门禁证据(`gate-callback.sh`)→ 完成
- 运行中 → `--wait` 等待最多 5 分钟
- 失败 → 进入自动修复循环
2. 自动修复循环(最多 3 轮):
a. `fetch-ci-logs.sh --failed-only` 获取失败 job 日志
b. AI 诊断根因(见错误模式目录)
c. 自动修复代码
d. 本地验证(`go vet ./...` / `npx tsc --noEmit`
e. `git commit && git push`
f. `check-ci-status.sh --trigger --wait` 等待新 CI
g. 通过 → 写入门禁证据 → 完成
h. 仍失败 → 下一轮(超过 3 轮 → AskUserQuestion 是否继续)
- 参数:`--trigger` 手动触发 CI`--wait` 等待完成,`--no-fix` 仅诊断不修复
**错误模式目录**
| 失败 Job | 错误模式 | 修复策略 |
|----------|---------|---------|
| architecture-gate | 架构 ratchet 违规 | 读取违规文件,用 service 层替代直接 database import |
| backend-lint (go vet) | `file.go:42: unreachable code` | 读取文件,修复具体问题 |
| backend-lint (gofmt) | `Files need gofmt:` | 运行 `gofmt -s -w` |
| backend-lint (go test) | `--- FAIL: TestXxx` | 读取测试和实现,修复根因 |
| frontend-lint (ESLint) | `warnings N > 4600` | 对比 main只修复新增警告 |
| frontend-lint (Prettier) | `unformatted N > 1000` | `npx prettier --write` 变更文件 |
| frontend-lint (TS) | `errors N > 60` | 对比 main只修复新增类型错误 |
**`/req test [REQ-ID]`** — 测试(前置:代码评审通过),遵循 dev-test 技能的 5-Gate 流程
**`/req deploy [--project <name>] [--env <env>]`** — 项目级批量部署:
**`/req deploy [--project <name>] [--env production]`** — 项目级批量部署Staging 已自动化push develop 即触发)
1. 收集待部署需求delivery_stage=testing + 全 test 任务 completed
2. AskUserQuestion 确认范围
3. `ai-proj task create` 创建部署批次任务
4. Deploy Gates DG1-DG6staging 部署 → 冒烟测试 → 回归 → 生产部署
5. `ai-proj task append-doc` 记录部署文档
6. `ai-proj req advance --id <id> --to released` 批量推进
3. `ai-proj task create` 创建部署批次任务linkRole=deploy
4. 部署前检查(变更检测、数据库迁移)
5. 执行 `./scripts/build-and-push.sh prod --detect --deploy --wait --verify`
6. **Deploy Gate 1: 健康检查**`/health` 返回 200
7. **Deploy Gate 2+3: PDV 验收**(为每个需求创建独立验收任务):
a. `ai-proj task create --title "【验收】PDV: {需求标题}"` 创建验收任务
b. `ai-proj req link --id <req_id> --task-ids <task_id> --link-role verification` 关联需求
c. 从需求关联任务中提取前端变更范围(页面路由、菜单项、关键 API
d. 生成验收检查清单(页面可达 + 菜单可见 + 基础渲染 + API 连通)
e. 用 Playwright 对部署环境执行冒烟测试:`E2E_BASE_URL=<部署环境URL> npx playwright test e2e/pdv/ --project=chromium`
f. 收集截图证据
g. `ai-proj task append-doc --id <task_id>` 附加验收文档(检查项表格 + 截图 + 结论)
h. **全部通过**`ai-proj task complete --id <task_id>` → Gate 2+3 放行
i. **任一失败** → 任务保持 in_progress**阻断推进**,报告失败项
8. `ai-proj task append-doc` 记录【部署】任务文档(构建日志 + 健康检查 + PDV 结果摘要)
9. `ai-proj req advance --id <id> --to released` 批量推进(仅 Gate 1-3 全部通过的需求)
**`/req done [REQ-ID]`** — 类型化归档门禁 + git commit + push + `ai-proj req archive --id <id>`
- **推断类型**:有 implementation → code无 implementation 有 prd/test → skill仅 deploy → ops
- **code 检查**delivery_stage=released + deploy 任务完成 + 部署文档 + 所有任务完成
- **code 检查**delivery_stage=released + deploy 任务完成 + verification 任务完成PDV 通过) + 部署文档 + 所有任务完成
- **skill 检查**delivery_stage≥testing + 所有任务完成
- **ops 检查**deploy 任务完成 + 所有任务完成
@@ -317,8 +420,10 @@ ai-proj task append-doc --id 5214 --content "# PRD: 用户认证功能\n..."
| design | 【评审】技术设计: {需求标题} | design |
| dev | 【开发-后端】{需求标题}、【开发-前端】{需求标题} | implementation |
| review | 【代码评审】{需求标题} | code_review |
| review | 【约定】{约定名称}bug 类需求convention flow 自动创建) | documentation |
| testing | 【测试】集成测试: {需求标题} | test |
| deploy | 由 `/req deploy` 批量创建 | deploy |
| released | 【验收】PDV: {需求标题}`/req deploy` 自动创建) | verification |
## 测试环境流程
@@ -337,7 +442,8 @@ ai-proj task append-doc --id 5214 --content "# PRD: 用户认证功能\n..."
| implementation | 【开发】 | dev | 50% |
| code_review | 【代码评审】 | review | 5% |
| test | 【测试】 | testing | 15% |
| deploy | 【部署】 | staging/released | 10% |
| deploy | 【部署】 | staging/released | 5% |
| verification | 【验收】 | released | 5% |
| documentation | 【文档】 | any | 5% |
## 标准任务结构
@@ -350,7 +456,9 @@ ai-proj task append-doc --id 5214 --content "# PRD: 用户认证功能\n..."
├── 🔍 review → 【代码评审】CR: {需求标题} (linkRole: code_review)
├── 🧪 testing → 【测试】集成测试: {需求标题} (linkRole: test)
├── 🚀 staging → 【部署】部署到 staging (linkRole: deploy)
└── 🏁 released → 【部署】部署到 prod (linkRole: deploy)
└── 🏁 released
├── 【部署】部署到 prod (linkRole: deploy)
└── 【验收】PDV: {需求标题} (linkRole: verification)
```
## ai-proj CLI 速查
@@ -374,187 +482,13 @@ ai-proj req tasks --id <id> # 查看关联任务
**开发阶段**: `backlog`, `analysis`, `design`, `dev`, `review`, `integration`, `testing`, `staging`, `released`
**linkRole**: `prd`, `design`, `implementation`, `code_review`, `test`, `deploy`, `regression`, `documentation`
## 详细阶段管理命令
### `/req phase [REQ-ID]`
查看需求当前开发阶段和任务状态。
**执行逻辑**
1. `get_requirement(id)` → 获取 `delivery_stage`
2. `get_requirement_tasks(id)` → 获取所有关联任务
3. 按 linkRole 分组展示,标注当前阶段任务完成度
**输出示例**
```
REQ-20260218-0013 | 阶段: dev (开发)
────────────────────────────────────
✅ analysis (评审)
✅ #6035 【评审】PRD: 需求全生命周期阶段化管理
▶ dev (开发) ← 当前阶段
🔄 #6042 【开发-后端】实现阶段管理 API [in_progress]
⬜ #6043 【开发-前端】阶段可视化组件 [todo]
⬜ review (代码评审)
⬜ testing (测试)
```
### `/req resume [REQ-ID]`
从上次中断的位置恢复工作。**会话被截断后的首选命令**。
**执行逻辑**
1. 若无 REQ-ID → `list_requirements(status=approved)` 找最近活跃需求
2. `get_requirement(id)` → 获取 delivery_stage
3. `get_requirement_tasks(id)` → 获取所有关联任务及状态
4. 汇总展示恢复上下文
**输出格式**
```
📋 恢复工作上下文
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
需求: REQ-20260218-0016 | 需求标题
状态: approved | 阶段: dev (开发)
📊 任务进度: 2/4 完成
✅ #6051 【开发-后端】实现 API
🔄 #6053 【开发-Skill】xxx [in_progress]
⬜ #6054 【开发-Skill】xxx [todo]
▶ 建议操作:
1. 继续任务 #6053当前 in_progress
2. 执行 /req next 推进阶段
```
### `/req regression [--module <name>] [--mode <mode>]`
**运行回归测试**。系统级持续质量活动。
- `--module` 指定模块,不指定则按影响域推断
- `--mode``impact`(影响域,默认)| `critical`(关键路径)| `full`(全量)
**执行逻辑**
1. 确定范围:指定 module → 直接运行;未指定 → `git diff` + `module-deps.json` 推断
2. 运行 `regression-suite/suites/` 下对应脚本
3. 对比上次运行结果,标记回归(上次 PASS + 本次 FAIL
4. 有回归 → AskUserQuestion「是否创建 bug 需求?」
## 辅助命令
**`/req link [REQ-ID] --task-id [TASK-ID]`** — 关联任务到需求
**`/req decompose [REQ-ID]`** — 分解需求为任务,自动加阶段前缀
**`/req generate-tasks [REQ-ID]`** — 根据 PRD 自动生成开发任务,带【开发】前缀
**`/req priority [REQ-ID] [low|medium|high]`** — 设置需求优先级
**`/req stats [REQ-ID|--all]`** — 查看需求统计信息
## 阶段任务 Checklist 模板
`/req next` 推进到新阶段时,通过 `create_stage_task` 自动创建建议任务:
### analysis评审
```
☐ 【评审】PRD: {需求标题} (linkRole: prd)
☐ 【评审】技术设计: {需求标题} (linkRole: design) [可选]
```
### design设计
```
☐ 【设计】技术方案: {需求标题} (linkRole: design)
```
### dev开发
```
☐ 【开发-后端】{需求标题} (linkRole: implementation)
☐ 【开发-前端】{需求标题} (linkRole: implementation) [可选]
```
### review代码评审
```
☐ 【代码评审】{需求标题} (linkRole: code_review)
```
### testing测试
```
☐ 【测试】单元测试: {需求标题} (linkRole: test)
☐ 【测试】集成测试: {需求标题} (linkRole: test) [可选]
```
### 部署(由 `/req deploy` 批量触发)
```
testing 完成 → 进入「待部署池」→ /req deploy 创建批次任务
```
**按需求类型的最低测试标准**
| 需求类型 | 最低测试要求 |
|----------|-------------|
| **code** | `go test` 或前端测试通过 + API 验证 + 截图验证 |
| **skill** | 关键词一致性 + 规则无歧义 + 边界情况(至少 3 项) |
| **ops** | 部署命令可执行 + 健康检查通过 |
## MCP 工具映射
| 命令 | MCP 工具 |
|------|----------|
| `/req` | `list_requirements` |
| `/req new` | `create_requirement` |
| `/req phase` | `get_requirement` + `get_requirement_tasks` |
| `/req next` | `advance_delivery_stage` + `create_stage_task` |
| `/req resume` | `get_requirement` + `get_requirement_tasks` |
| `/req dev` | `get_requirement` + `get_requirement_tasks` + `start_task_with_timer` |
| `/req cr` | `get_requirement_tasks` + Git diff |
| `/req test` | `req-test-gate` 5-Gate 流程 |
| `/req deploy` | Deploy Gates DG1-DG6 |
| `/req regression` | `git diff` + 回归套件 |
| `/req done` | 类型推断 + 检查清单 + `archive_requirement` |
| `/req review` | `submit_requirement` |
| `/req review pass` | `approve_requirement` |
| `/req link` | `link_tasks_to_requirement` |
## 环境选择
> **重要**:正式需求应直接在**生产环境** (`mcp__ai-proj-prod__*`) 创建。
> 仅在功能测试、流程验证时使用开发环境 (`mcp__ai-proj-dev__*`)。
> 开发环境同步到生产时,`due_date`、`reviewer_id`、`allow_self_approve` 等字段会丢失,需手动补充。
## Hook 自动同步
需求操作自动触发同步,无需手动执行:
| 事件 | 触发操作 |
|------|----------|
| `requirement.created` | 同步到远程 |
| `requirement.approved` | 同步需求和任务 |
| `task.completed` | 同步任务状态 |
| `requirement.archived` | 最终同步 + 思源笔记 |
**手动同步**
```typescript
mcp__ai-proj__sync_requirement_to_remote(requirementId)
mcp__ai-proj__batch_sync_tasks_to_remote(taskIds)
```
**同步已知限制**
| 字段 | 同步支持 | 说明 |
|------|----------|------|
| title, description, status, priority | ✅ | 正常同步 |
| **due_date** | ❌ | 不会同步,需手动补充 |
| reviewer_id | ❌ | 不会同步 |
| allow_self_approve | ❌ | 不会同步 |
## 思源笔记集成
归档时自动同步 5 阶段文档到思源笔记:
- 路径:`需求管理/REQ-XXXX/`
- 文档01-PRD.md ~ 05-生命周期总结.md
- 手动同步:`/req sync-siyuan [REQ-ID]`
**linkRole**: `prd`, `design`, `implementation`, `code_review`, `test`, `deploy`, `verification`, `regression`, `documentation`
## 相关技能
| 技能 | 用途 |
|------|------|
| `req-prd` | PRD 文档编写 + 评审方法论 |
| `req-test-gate` | 测试 5-Gate + Deploy Gates |
| `req-dev` | PRD 到代码转换、开发计划 |
| `req-prototype` | Stitch 原型生成 + 迭代 |
| `dev-test` | 测试 + 质量门禁 |
| `req-test-gate` (harness) | 工程约束方法论。Gate 0-2 的约定检查由项目本地脚本定义,方法论见 `/harness` 命令 |

View File

@@ -1,7 +1,7 @@
{
"name": "req-prd-plugin",
"description": "Plugin for req-prd",
"version": "1.0.0",
"description": "产品需求设计技能。PRD 文档编写、需求分析、用户故事、对比式分析。纯产品视角,不含技术实现。",
"version": "2.0.0",
"author": {
"name": "qiudl"
}

View File

@@ -1,6 +1,6 @@
---
name: req-prd
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划、PRD 评审。当用户提到产品设计、PRD、需求文档、功能规划、用户故事、PRD 评审相关任务时自动激活。
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划。当用户提到产品设计、PRD、需求文档、功能规划、用户故事相关任务时自动激活。
---
# 产品需求设计 Skill (req-prd)
@@ -9,248 +9,23 @@ description: 产品设计与需求管理。用于 PRD 文档编写、需求分
本技能用于辅助产品设计和需求管理工作,包括:
- PRD 文档编写与管理
- **参考对象对比式 PRD 编写**(核心能力)
- 需求分析与优先级排序
- 用户故事创建
- 功能设计与规划
- 与 ai-proj 任务系统集成
---
## 参考对象对比式 PRD 编写
当进行**系统平移、功能迁移、竞品借鉴**时,应采用对比分析法编写 PRD确保新系统功能完整且有所改进。
### 适用场景
| 场景 | 说明 | 示例 |
|------|------|------|
| 系统平移 | 旧系统迁移到新技术栈 | 酷采2.0 → 酷采3.0 |
| 功能借鉴 | 参考竞品功能设计 | 参考飞书设计协作功能 |
| 版本升级 | 基于当前版本优化 | V1.0 → V2.0 重构 |
### 对比分析工作流
```
1. 确定参考对象
├── 识别参考系统(可以是多个)
├── 获取访问权限(测试环境、源代码)
└── 明确对比目标
2. 参考对象分析
├── 功能调研(前端页面操作)
├── 数据模型分析(数据库表结构)
├── 业务逻辑分析(后端代码)
└── API 接口分析
3. 对比分析
├── 功能对比表(保留/优化/新增/废弃)
├── 数据模型对比(字段映射、新增字段)
├── 技术架构对比
└── 用户体验对比
4. PRD 编写
├── 背景说明(明确参考来源)
├── 功能需求(标注来源与变更)
├── 数据设计(标注字段来源)
└── 实现建议
```
### 对比式 PRD 模板
```markdown
# [功能模块名称] PRD
## 1. 文档概述
### 1.1 文档信息
| 项目 | 内容 |
|------|------|
| 文档名称 | [模块名称] 需求文档 |
| 版本 | V1.0 |
| 创建日期 | [日期] |
| **需求来源** | **[参考系统名称] 平移/借鉴** |
| **参考系统** | **[参考系统访问地址]** |
### 1.2 背景说明
本需求文档基于 **[参考系统]** 的 [模块名称] 功能分析,将其平移至 [目标系统]。
**参考系统信息**
- 系统地址:[URL]
- 技术栈:[技术栈描述]
- 源码位置:[源码路径](如有)
**插件扩展**
- `req-compare` — 对比式 PRD 编写(系统平移/竞品借鉴时激活)
- `req-prototype` — UI 原型生成
---
## 2. 参考系统分析
## 对比式 PRD 编写
### 2.1 功能截图
[插入参考系统功能截图]
> 系统平移、竞品借鉴、版本升级时,使用 `req-compare` 插件进行对比分析。
> 该插件包含完整的对比工作流、对比式 PRD 模板和竞品分析模板。
### 2.2 数据模型(参考系统)
```sql
-- 参考系统表结构
CREATE TABLE [表名] (
-- 从源代码/数据库提取
);
```
### 2.3 API 接口(参考系统)
| 接口 | 方法 | 说明 |
|------|------|------|
| /api/xxx | GET/POST | [描述] |
### 2.4 业务逻辑(参考系统)
- 核心业务规则摘要
- 数据校验规则
- 状态流转逻辑
---
## 3. 功能对比分析
### 3.1 功能对比表
| 序号 | 功能 | 参考系统 | 目标系统 | 变更类型 | 说明 |
|------|------|----------|----------|----------|------|
| 1 | [功能1] | ✅ | ✅ | 保留 | 直接平移 |
| 2 | [功能2] | ✅ | ✅+ | 优化 | [优化内容] |
| 3 | [功能3] | ❌ | ✅ | 新增 | [新增原因] |
| 4 | [功能4] | ✅ | ❌ | 废弃 | [废弃原因] |
### 3.2 数据模型对比
| 参考系统字段 | 目标系统字段 | 类型 | 变更 | 说明 |
|--------------|--------------|------|------|------|
| id (varchar) | id (bigint) | PK | 优化 | 改用自增ID |
| company_id | tenant_id | FK | 重命名 | 统一租户字段 |
| -- | created_by | bigint | 新增 | 审计字段 |
### 3.3 技术架构对比
| 层次 | 参考系统 | 目标系统 |
|------|----------|----------|
| 后端框架 | [如: Spring Boot] | [如: Go Gin] |
| 前端框架 | [如: Vue 2] | [如: React 18] |
| 数据库 | [如: MySQL] | [如: PostgreSQL] |
---
## 4. 目标系统设计
### 4.1 功能清单
| 序号 | 功能 | 优先级 | 来源 | 说明 |
|------|------|--------|------|------|
| 1 | [功能] | P0 | 平移 | 从参考系统平移 |
### 4.2 数据模型(目标系统)
```sql
-- 目标系统表结构(基于对比分析设计)
CREATE TABLE [] (
id BIGINT PRIMARY KEY,
-- 字段设计...
);
```
### 4.3 API 设计(目标系统)
| 接口 | 方法 | 说明 | 参考接口 |
|------|------|------|----------|
| /api/v1/xxx | GET | [描述] | 参考 /api/xxx |
### 4.4 业务规则
- [ ] 规则1沿用参考系统
- [ ] 规则2优化调整
---
## 5. 实现建议
### 5.1 开发顺序
1. 数据模型迁移
2. 后端 API 实现
3. 前端页面开发
4. 数据迁移脚本
### 5.2 注意事项
- 参考系统中 [xxx] 逻辑需要特别注意
- 新系统中需改进 [xxx] 问题
```
---
### 参考对象分析工具
#### 1. 前端分析
```bash
# 启动浏览器调试模式macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
--remote-debugging-port=9222 \
--user-data-dir=/tmp/chrome-debug
# 访问参考系统,截图、分析交互
```
#### 2. 后端代码分析
```bash
# 搜索相关模型
grep -r "class.*Model" --include="*.java" /path/to/legacy/
# 搜索相关控制器
grep -r "@Controller\|@RestController" --include="*.java" /path/to/legacy/
```
#### 3. 数据库分析
```sql
-- 查看表结构
SHOW CREATE TABLE table_name;
-- 查看字段注释
SELECT COLUMN_NAME, COLUMN_COMMENT
FROM information_schema.COLUMNS
WHERE TABLE_NAME = 'table_name';
```
---
### 示例酷采3.0标签管理模块
以下是基于酷采2.0平移的标签管理模块对比分析示例:
#### 参考系统酷采2.0
**数据模型**
```sql
-- 酷采2.0 prd_product_label 表
CREATE TABLE `prd_product_label` (
`id` varchar(64) NOT NULL,
`label_name` varchar(256) DEFAULT NULL,
`company_id` varchar(64) DEFAULT NULL,
`input_user_id` varchar(64) DEFAULT NULL,
`input_user_name` varchar(64) DEFAULT NULL,
`input_time` datetime DEFAULT NULL,
`update_user_id` varchar(64) DEFAULT NULL,
`update_user_name` varchar(64) DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
`version` bigint(20) DEFAULT 0,
`is_delete` tinyint(1) DEFAULT 0,
`status` tinyint(1) DEFAULT 1,
`remark` varchar(512) DEFAULT NULL,
`sort_no` int(11) DEFAULT 0,
PRIMARY KEY (`id`)
);
```
**代码位置**
- 后端: `cool_lining/module-provider/.../dao/model/prd/PrdProductLabel.java`
- 前端: `ln_admin/src/views/module/prd/product_label/`
#### 目标系统酷采3.0)设计
**数据模型对比**
| 酷采2.0 | 酷采3.0 | 变更 |
|---------|---------|------|
| id (varchar) | id (bigint) | 改用自增ID |
| company_id | tenant_id | 统一租户标识 |
| input_user_id | created_by | 简化字段命名 |
| input_time | created_at | 统一时间字段 |
| is_delete | deleted_at | 改用软删除时间戳 |
**触发方式**当需求涉及参考系统时req-prd 自动推荐激活 req-compare 插件。
---
@@ -304,7 +79,11 @@ CREATE TABLE `prd_product_label` (
[流程图或步骤描述]
### 4.2 界面原型
[原型链接或描述]
> 使用 `/req prototype [REQ-ID]` 基于 PRD 自动生成 Stitch 原型。
> 生成后截图将自动回填到此章节。
[执行 `/req prototype` 后自动填充]
## 5. 技术要求
### 5.1 性能要求
@@ -519,36 +298,9 @@ mcp__ai-proj__export_task_document_to_file
---
## 竞品分析模板
## 竞品分析
### 分析框架
```markdown
# [竞品名称] 分析
## 1. 产品概述
- 定位:
- 核心功能:
- 目标用户:
## 2. 功能对比
| 功能 | 我们 | 竞品A | 竞品B |
|------|------|-------|-------|
| 功能1 | ✅/❌/部分 | ... | ... |
## 3. 优劣势分析
### 优势
1. ...
### 劣势
1. ...
## 4. 可借鉴点
- ...
## 5. 差异化策略
- ...
```
> 竞品分析模板已移至 `req-compare` 插件。涉及竞品对比时自动激活。
---
@@ -606,20 +358,22 @@ mcp__ai-proj__export_task_document_to_file
- [ ] 操作可撤销
- [ ] 符合用户习惯
### 技术方案检查
### 非功能需求检查
- [ ] 技术可行性验证
- [ ] 性能影响评估
- [ ] 扩展性考虑
- [ ] 安全性审查
- [ ] 兼容性测试
- [ ] 性能要求已量化(响应时间、并发量)
- [ ] 安全需求已明确(权限、数据保护)
- [ ] 兼容性要求已定义(浏览器、设备)
- [ ] 可用性目标已设定
> **技术方案可行性检查**在 design 阶段由 `req-design` 技能完成。
---
## 常用工具
### 原型设计
- Figma
- **Stitch** (Google AI) — 集成在 `/req prototype`,自动从 PRD 生成原型
- Figma — 手动精细设计
- Sketch
- Axure
@@ -660,111 +414,31 @@ mcp__ai-proj__export_task_document_to_file
---
## PRD 评审方法论
## Memory 隔离规则(强制,源自 devflow-claude 借鉴)
PRD 评审是需求流程的关键质量关卡。
**规则:本 skill 涉及模板/文档产出的命令禁止受 auto-memory 影响产出物。**
### 评审流程
### 禁止行为
1. 不得根据 memory 中的偏好跳过或合并 PRD 模板章节
2. 不得用 memory 里的历史需求/项目内容填充当前 PRD
3. 不得根据 memory 反馈调整 PRD 章节顺序、表格列数、标题层级
4. 不得读取 `~/.claude/projects/*/memory/` 辅助生成 PRD 正文
```
PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据模型 → API 审查 → 结论
```
### 允许行为
- memory 可影响**交互风格**(提问详略、确认节奏、语气)
- memory 可指导**命令选择**(如根据用户习惯推荐先走 req-compare 还是 req-prd
- memory 可影响**非产出文本**(如对话中的说明)
### 结构完整性检查
### Why
auto-memory 设计用于跨会话建立用户画像。但 PRD/需求文档是正式产出物,必须由**模板结构 + 当前输入**决定,不能因 memory 中的偏好自作主张调整结构,否则会导致:
- 模板章节漂移(用户不知道为什么这次少了一章)
- 历史项目内容污染(张冠李戴)
- 产出不可复现
| 检查项 | 必须 | 说明 |
|--------|:----:|------|
| 基本信息 | ✓ | 编号、标题、日期、作者 |
| 需求背景 | ✓ | 为什么需要这个功能 |
| 目标用户 | ✓ | 面向的用户群体 |
| 功能描述 | ✓ | 详细功能需求 |
| 数据模型 | ✓ | 数据库表结构 |
| API 设计 | ✓ | RESTful 接口 |
| 验收标准 | ✓ | 验收条件 |
| 用户故事 | ○ | As a... I want... |
| 页面原型 | ○ | 界面布局 |
| 非功能需求 | ○ | 性能、安全 |
### How to apply
执行 `/req prd` / PRD 编写 / 需求描述生成等命令时:
- 仅读取:模板文件、用户当前输入、引用的已有需求文档
- 不读取memory 目录下的任何文件
- 产出前自检:章节数量和顺序与模板完全一致
### 需求清晰度SMART 原则)
| 原则 | 检查点 |
|------|--------|
| **S**pecific | 描述是否具体明确 |
| **M**easurable | 是否有量化指标 |
| **A**chievable | 技术上是否可行 |
| **R**elevant | 是否与业务目标相关 |
| **T**ime-bound | 是否有时间范围 |
**示例**
- ❌ "用户可以搜索需求"
- ✅ "用户可按编号精确搜索、按标题模糊搜索、按状态筛选,结果分页显示"
### 技术可行性
| 维度 | 评估内容 |
|------|----------|
| 技术栈兼容 | 现有栈是否支持 |
| 架构影响 | 是否需修改架构 |
| 第三方依赖 | 是否引入新依赖 |
| 性能影响 | 潜在性能问题 |
| 安全考量 | 安全风险 |
### 数据模型验证
| 检查项 | 说明 |
|--------|------|
| 表结构 | 字段类型、约束、索引 |
| 关联关系 | 外键、多对多 |
| 命名规范 | 符合项目规范 |
| 扩展性 | 预留扩展字段 |
| 查询性能 | 常用查询有索引 |
### API 设计审查
| 检查项 | 标准 |
|--------|------|
| RESTful | URL 用名词HTTP 方法语义正确 |
| 响应格式 | `{success, data, message}` |
| 错误处理 | 明确的错误码 |
| 分页 | `?page=1&page_size=20` |
| 版本控制 | `/api/v1/...` |
### 评审结论模板
**通过**
```
✅ PRD 评审通过
【结论】文档完整,需求清晰,方案可行,建议批准。
【肯定】需求背景清晰、数据模型合理、API 规范
【建议】(非阻塞)补充性能测试用例
【评审人】xxx 【时间】2026-xx-xx
```
**驳回**
```
❌ PRD 评审驳回
【原因】
1. 数据模型缺少索引
2. API 缺少错误处理
3. 搜索需求描述模糊
【修改要求】
□ 补充索引设计
□ 明确错误码
□ 细化搜索实现
【驳回人】xxx 【时间】2026-xx-xx
```
### 常见驳回原因
| 类别 | 问题 | 建议 |
|------|------|------|
| 结构缺失 | 缺数据模型或 API | 补充技术设计 |
| 需求模糊 | 描述不具体 | 按 SMART 重写 |
| 边界不清 | 缺异常处理 | 补充边界条件 |
| 设计缺陷 | 模型/API 不合理 | 重新设计 |
| 范围过大 | 难以实现 | 拆分为多需求 |
| 验收不明 | 缺验收标准 | 补充验收条件 |
**参考**devflow-claude 的 `plugins/req/commands/_common.md` 同名规则。

View File

@@ -0,0 +1,8 @@
{
"name": "req-prototype-plugin",
"description": "Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,164 @@
---
name: req-prototype
description: Stitch 原型生成与迭代。基于 PRD 文档自动生成 UI 原型,支持编辑和变体生成。当执行 /req prototype 或需要生成界面原型时使用。
arguments: [REQ-ID] [--device desktop|mobile|tablet] [--model pro|flash] [--prompt "..."]
---
# Stitch 原型设计 Skill (req-prototype)
## 概述
基于 PRD 文档自动生成 Stitch UI 原型,插入在 PRD 编写完成后、submit 评审前。
**核心流程**:读取 PRD → 提取 UI 描述 → 转英文 prompt → 调用 Stitch API → 截图回填 PRD
## 前置条件
执行前必须检查:
| 检查项 | 方式 | 失败处理 |
|--------|------|----------|
| 需求存在 | `ai-proj req get --id <id>` | 报错:需求不存在 |
| PRD 文档存在 | `ai-proj req tasks --id <id>` 找 linkRole=prd 任务 + 检查文档 | 报错:请先执行 req-prd 编写 PRD |
| PRD 包含 UI 描述 | 检查 PRD 中「功能需求」「交互设计」「界面原型」章节 | 警告PRD 未包含 UI 相关描述,建议先补充 |
## 子命令
### 1. `/req prototype [REQ-ID]` — 生成原型
**流程**
```
1. 前置条件检查
2. 读取 PRD 文档ai-proj task get-doc
3. 提取 UI 相关内容(功能需求 + 交互设计章节)
4. PRD → Stitch Prompt 转换(中文 → 英文设计描述)
5. 创建 Stitch 项目mcp__stitch__create_project
6. 生成页面mcp__stitch__generate_screen_from_text
7. 获取截图mcp__stitch__get_screen
8. 回填 PRD「4.2 界面原型」章节
```
**参数**
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `--device` | `desktop` | 设备类型desktop / mobile / tablet |
| `--model` | `pro` | 模型pro (GEMINI_3_1_PRO) / flash (GEMINI_3_FLASH) |
### 2. `/req prototype edit [REQ-ID] --prompt "..."` — 编辑原型
**流程**
```
1. 从 PRD「4.2 界面原型」元数据获取 stitch_project_id 和 screen_id
2. 调用 mcp__stitch__edit_screens 编辑指定页面
3. 获取更新后截图
4. 更新 PRD「4.2 界面原型」章节
```
### 3. `/req prototype variant [REQ-ID]` — 生成变体
**流程**
```
1. 从 PRD「4.2 界面原型」元数据获取 stitch_project_id 和 screen_id
2. 调用 mcp__stitch__generate_variants 生成变体
3. 展示所有变体截图供用户选择
4. 用户选择后更新 PRD
```
**变体参数**
| 参数 | 选项 | 说明 |
|------|------|------|
| `creativeRange` | REFINE / EXPLORE / REIMAGINE | 创意程度 |
| `aspects` | LAYOUT / COLOR_SCHEME / IMAGES / TEXT_FONT / TEXT_CONTENT | 变化维度 |
## PRD → Stitch Prompt 转换策略
从 PRD 提取以下章节内容,转换为英文设计 prompt
1. **功能需求**(第 3 章)→ 提取功能列表和交互描述
2. **交互设计**(第 4 章)→ 提取用户流程和界面描述
3. **目标用户**(第 2 章)→ 确定设计风格和复杂度
**转换模板**
```
Design a [device_type] web application for [product_name].
Target users: [user_description]
Key features:
- [feature_1]: [description]
- [feature_2]: [description]
...
User flow:
1. [step_1]
2. [step_2]
...
UI requirements:
- [layout_requirement]
- [interaction_requirement]
...
Style: Clean, modern, professional SaaS interface with clear navigation.
```
## Stitch API 参数映射
| 用户参数 | Stitch API 参数 | 值映射 |
|----------|-----------------|--------|
| `--device desktop` | `deviceType` | `DESKTOP` |
| `--device mobile` | `deviceType` | `MOBILE` |
| `--device tablet` | `deviceType` | `TABLET` |
| `--model pro` | `modelId` | `GEMINI_3_1_PRO` |
| `--model flash` | `modelId` | `GEMINI_3_FLASH` |
## PRD 回填逻辑
定位 PRD 中 `### 4.2 界面原型` 章节,替换内容为:
```markdown
### 4.2 界面原型
> Stitch AI 自动生成原型,基于本 PRD 功能需求和交互设计。
**原型预览**
| 页面 | 截图 | 说明 |
|------|------|------|
| [screen_name_1] | ![screenshot](screenshot_url_1) | [描述] |
| [screen_name_2] | ![screenshot](screenshot_url_2) | [描述] |
**Stitch 项目信息**
```yaml
stitch_project_id: "<project_id>"
screens:
- id: "<screen_id_1>"
name: "<screen_name_1>"
device: "<device_type>"
- id: "<screen_id_2>"
name: "<screen_name_2>"
device: "<device_type>"
model: "<model_id>"
generated_at: "<timestamp>"
```
**编辑原型**`/req prototype edit [REQ-ID] --prompt "修改说明"`
**生成变体**`/req prototype variant [REQ-ID]`
```
## 异常处理
| 异常 | 处理 |
|------|------|
| 需求无 PRD 文档 | 报错:`请先使用 req-prd 技能编写 PRD 文档` |
| PRD 无 UI 相关描述 | 警告并询问:`PRD 未包含明确的 UI 描述,是否基于功能需求自动推断?` |
| Stitch API 超时 | 提示:`Stitch 生成耗时约 1-2 分钟,请稍候...` 超过 3 分钟报错 |
| Stitch API 返回错误 | 展示错误信息,建议调整 prompt 或更换模型 |
| PRD 无「4.2 界面原型」章节 | 在「## 4. 交互设计」末尾自动追加该章节 |
| 已有原型元数据 | 询问:`已存在原型,是否覆盖?` |

View File

@@ -0,0 +1,6 @@
{
"name": "req-research-plugin",
"description": "需求调研插件。代码审计、数据库分析、现有功能调研。挂载在 analysis 阶段,需要深度调研时激活。",
"version": "1.0.0",
"author": { "name": "qiudl" }
}

View File

@@ -0,0 +1,124 @@
---
name: req-research
description: 需求调研插件。代码审计、数据库分析、现有功能调研、技术可行性评估。挂载在 analysis 阶段,需要深度调研时由 req-prd 推荐激活。
---
# 需求调研插件 (req-research)
## 概述
当 PRD 编写需要**深入了解现有系统**时使用。提供结构化的调研方法。
**触发条件**
- 需求涉及修改现有功能(需了解当前实现)
- 需求涉及数据库表结构变更
- 需要技术可行性评估
## 调研方法
### 1. 前端功能调研
```bash
# 启动本地开发环境
cd frontend && npm start
# 访问相关页面,记录:
# - 页面布局和交互流程
# - 表单字段和校验规则
# - 列表列和筛选条件
# - 异常情况处理(空状态、错误提示)
```
**调研模板**
```markdown
### 页面: [页面名称] ([URL])
- **功能**: [功能描述]
- **字段**: [列出所有字段]
- **操作**: [CRUD/筛选/排序/导出]
- **校验**: [表单校验规则]
- **截图**: [如有]
```
### 2. 后端代码审计
```bash
# 搜索相关模型
Grep(pattern="type.*struct", path="backend/models", glob="*xxx*.go")
# 搜索相关 Handler
Grep(pattern="func.*Handler.*xxx", path="backend/handlers")
# 搜索相关路由
Grep(pattern="xxx", path="backend/routes")
# 搜索相关 Service
Grep(pattern="func.*Service.*xxx", path="backend/services")
```
**审计模板**
```markdown
### 模块: [模块名]
- **Model**: `backend/models/xxx.go` — [字段数]个字段
- **Repository**: `backend/database/xxx_repository.go` — [方法数]个方法
- **Service**: `backend/services/xxx_service.go` — [方法数]个方法
- **Handler**: `backend/handlers/xxx_handler.go` — [接口数]个接口
- **Route**: `backend/routes/xxx_routes.go`
- **关键业务逻辑**: [描述]
```
### 3. 数据库分析
```bash
# 查看表结构(本地)
psql -U ai_user -d ai_project -c "\d table_name"
# 查看数据量
psql -U ai_user -d ai_project -c "SELECT COUNT(*) FROM table_name"
# 查看索引
psql -U ai_user -d ai_project -c "\di table_name*"
```
**分析模板**
```markdown
### 表: [表名]
- **字段数**: N
- **数据量**: ~N 行
- **索引**: [列出索引]
- **关联**: [外键关系]
- **特殊字段**: [JSON/Array/Enum 等]
```
### 4. API 分析
```bash
# 查看 Swagger 文档
open http://localhost:8080/swagger/index.html
# 搜索 API 路由
Grep(pattern="GET|POST|PUT|DELETE.*xxx", path="backend/routes")
```
## 调研报告模板
```markdown
## 调研报告 — {需求标题}
### 1. 现有功能
[页面/功能调研结果]
### 2. 代码结构
[代码审计结果,按分层列出]
### 3. 数据库现状
[表结构、数据量、索引]
### 4. 技术可行性
| 方案 | 优点 | 缺点 | 工时预估 |
|------|------|------|---------|
| 方案A | ... | ... | Xh |
| 方案B | ... | ... | Xh |
### 5. 建议
[推荐方案及原因]
```

View File

@@ -0,0 +1,8 @@
{
"name": "req-review-plugin",
"description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,124 @@
---
name: req-review
description: PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。
---
# PRD 评审方法论
PRD 评审是需求流程的关键质量关卡。
## 评审流程
```
PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据模型 → API 审查 → 结论
```
## 结构完整性检查
| 检查项 | 必须 | 说明 |
|--------|:----:|------|
| 基本信息 | ✓ | 编号、标题、日期、作者 |
| 需求背景 | ✓ | 为什么需要这个功能 |
| 目标用户 | ✓ | 面向的用户群体 |
| 功能描述 | ✓ | 详细功能需求 |
| 数据模型 | ✓ | 数据库表结构 |
| API 设计 | ✓ | RESTful 接口 |
| 验收标准 | ✓ | 验收条件 |
| 用户故事 | ○ | As a... I want... |
| 页面原型 | ○ | 如有 Stitch 原型则必审:布局合理性、与 PRD 描述一致性 |
| 非功能需求 | ○ | 性能、安全 |
## 需求清晰度SMART 原则)
| 原则 | 检查点 |
|------|--------|
| **S**pecific | 描述是否具体明确 |
| **M**easurable | 是否有量化指标 |
| **A**chievable | 技术上是否可行 |
| **R**elevant | 是否与业务目标相关 |
| **T**ime-bound | 是否有时间范围 |
**示例**
- ❌ "用户可以搜索需求"
- ✅ "用户可按编号精确搜索、按标题模糊搜索、按状态筛选,结果分页显示"
## 技术可行性
| 维度 | 评估内容 |
|------|----------|
| 技术栈兼容 | 现有栈是否支持 |
| 架构影响 | 是否需修改架构 |
| 第三方依赖 | 是否引入新依赖 |
| 性能影响 | 潜在性能问题 |
| 安全考量 | 安全风险 |
## 数据模型验证
| 检查项 | 说明 |
|--------|------|
| 表结构 | 字段类型、约束、索引 |
| 关联关系 | 外键、多对多 |
| 命名规范 | 符合项目规范 |
| 扩展性 | 预留扩展字段 |
| 查询性能 | 常用查询有索引 |
## API 设计审查
| 检查项 | 标准 |
|--------|------|
| RESTful | URL 用名词HTTP 方法语义正确 |
| 响应格式 | `{success, data, message}` |
| 错误处理 | 明确的错误码 |
| 分页 | `?page=1&page_size=20` |
| 版本控制 | `/api/v1/...` |
## 界面原型检查(如有)
当 PRD 包含 Stitch 生成的原型时,评审人应检查:
| 检查项 | 说明 |
|--------|------|
| 页面覆盖 | 原型页面覆盖了 PRD 中描述的主要功能 |
| 布局一致 | 布局与 PRD 功能描述一致(无遗漏关键元素) |
| 交互合理 | 导航、表单、操作按钮逻辑合理 |
| 数据展示 | 列表、详情、表单字段完整 |
## 评审结论模板
**通过**
```
✅ PRD 评审通过
【结论】文档完整,需求清晰,方案可行,建议批准。
【肯定】需求背景清晰、数据模型合理、API 规范
【建议】(非阻塞)补充性能测试用例
【评审人】xxx 【时间】2026-xx-xx
```
**驳回**
```
❌ PRD 评审驳回
【原因】
1. 数据模型缺少索引
2. API 缺少错误处理
3. 搜索需求描述模糊
【修改要求】
□ 补充索引设计
□ 明确错误码
□ 细化搜索实现
【驳回人】xxx 【时间】2026-xx-xx
```
## 常见驳回原因
| 类别 | 问题 | 建议 |
|------|------|------|
| 结构缺失 | 缺数据模型或 API | 补充技术设计 |
| 需求模糊 | 描述不具体 | 按 SMART 重写 |
| 边界不清 | 缺异常处理 | 补充边界条件 |
| 设计缺陷 | 模型/API 不合理 | 重新设计 |
| 范围过大 | 难以实现 | 拆分为多需求 |
| 验收不明 | 缺验收标准 | 补充验收条件 |

View File

@@ -1,6 +1,6 @@
{
"name": "req-test-gate-plugin",
"description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5,含前后端联调+视觉验证)、部署级验证(Deploy Gates)、持续回归(Regression)。",
"description": "测试与质量门禁制度。覆盖需求级测试(Gates 1-5)、部署级验证(Deploy Gates)、持续回归(Regression)、Harness Engineering 工程约束方法论Ratchet、约定建立、门禁层级。",
"version": "1.0.0",
"author": {
"name": "qiudl"

View File

@@ -1,6 +1,7 @@
---
name: req-test-gate
description: 测试与质量门禁制度。覆盖需求级测试(Gates 1-5,含前后端联调+视觉验证)、部署级验证(Deploy Gates)、持续回归(Regression)。
description: 测试与质量门禁制度。覆盖需求级测试(Gates 1-5)、部署级验证(Deploy Gates)、持续回归(Regression)、Harness Engineering 工程约束方法论Ratchet、约定建立、门禁层级。当用户提到质量门禁、架构约束、约定检查、ratchet、harness 相关任务时自动激活
arguments: <subcommand> [args]
---
# 测试与质量门禁制度 (req-test-gate) v2.1
@@ -36,12 +37,13 @@ Gate 5: 回归贡献检查(按 scope 区分贡献形式)
通过 → 允许 /req next 推进到待部署池
```
## Gate 0: Scope 分级(自动)
## Gate 0: Scope 分级 + 约定检查(自动)
**从 `git diff` 自动推断变更范围,决定后续 Gate 的裁剪策略。**
**两件事**:① `git diff` 推断变更范围;② 运行项目内所有约定检查脚本。
### 0A: Scope 分级
```bash
# 自动推断逻辑
git diff main...HEAD --name-only | classify_scope
```
@@ -56,6 +58,43 @@ git diff main...HEAD --name-only | classify_scope
**scope 影响全部后续 Gate**,在测试报告中必须标注。
### 0B: 约定检查Harness 自动执行)
**自动发现并运行项目内所有 `scripts/check-*.sh` 脚本。**
```bash
# 自动执行逻辑
for script in scripts/check-*.sh; do
[ -x "$script" ] && bash "$script" --ci
done
```
| 结果 | 处理 |
|------|------|
| 全部 PASS | Gate 0 通过,继续 Gate 1 |
| 有 FAIL | **阻塞**,按下方「失败处理」修复后重新 `/req test` |
| 无 scripts/check-*.sh | 跳过(项目未建立约定检查) |
**失败处理**(区分脚本类型):
| 脚本类型 | 判断方法 | 修复方式 |
|---------|---------|---------|
| Hard wall纯检测 | 脚本无 baseline 文件 | 修改代码消除违规 |
| Ratchet基线对比 | 脚本有 `.*-baseline.json` | 修改代码降低违规数,**或**确认是故意增加 → `./scripts/check-{name}.sh baseline` 更新基线 + AskUserQuestion 确认 |
> 更新基线是有意识的决策(如重构导致临时增加),不能静默执行。
**报告格式**
```
### 约定检查 (Gate 0B)
| 脚本 | 结果 | 详情 |
|------|------|------|
| check-architecture.sh | ✅ PASS | 5 rules, all within baseline |
| check-modal-safety.sh | ✅ PASS | 0 violations |
```
> 这样 Harness 建立的约定脚本会在每次 `/req test` 时自动运行,无需手动执行 `/harness report`。
---
## Gate 1: 前置条件检查
@@ -437,9 +476,10 @@ DG6: 生产部署(不可跳过) → 健康检查+文档
### `/req test` 增强
```
v1: Gate 1 → Gate 2 → Gate 3 → Gate 4
v1: Gate 1 → Gate 2 → Gate 3 → Gate 4
v2: Gate 1 → Gate 2(2A→2B→2C→2D→2E) → Gate 3 → Gate 4 → Gate 5
v2.1: Gate 0(scope) → Gate 1 → Gate 2(2A→2B→2C→2D→2E→2F按scope裁剪) → Gate 3 → Gate 4 → Gate 5
v2.1: Gate 0(scope) → Gate 1 → Gate 2(2A→2B→2C→2D→2E→2F) → Gate 3 → Gate 4 → Gate 5
v3: Gate 0A(scope) + 0B(约定检查) → Gate 1 → Gate 2(按scope裁剪) → Gate 3 → Gate 4 → Gate 5
```
### `/req next` testing→staging 门禁
@@ -449,3 +489,52 @@ v2.1: Gate 0(scope) → Gate 1 → Gate 2(2A→2B→2C→2D→2E→2F按scope
### `/req deploy` 部署门禁
在 req-deploy 流程前增加 Deploy Gates (DG1-DG6) 检查。
---
## Harness Engineering — 工程约束方法论
**项目级基础设施**的建立和维护方法论,与上述需求级门禁互补。
> 详见 [harness-engineering.md](harness-engineering.md) 完整文档。
### 核心理念
**建立自动化护栏防止新违规,同时允许渐进式清理遗留问题。**
三大支柱:
1. **Ratchet** — 遗留违规数只能减不能增 → [ratchet-pattern.md](ratchet-pattern.md)
2. **约定建立** — 每个 bug 修复后立即建立约定和检测 → [convention-flow.md](convention-flow.md)
3. **门禁层级** — 按项目成熟度逐级引入 → [project-bootstrap.md](project-bootstrap.md)
### `/harness` 命令集(手动可用 + 自动嵌入)
| 命令 | 手动 | 自动触发 |
|------|------|---------|
| `/harness assess` | 随时 | 首次 `/req dev` |
| `/harness init [level]` | 随时 | — |
| `/harness convention [name]` | 随时 | `/req cr` + bug 类型需求 |
| `/harness report` | 随时 | `/req test` Gate 0B |
### 模板
`templates/` 目录提供可复用的脚本模板:
- [ratchet-script.md](templates/ratchet-script.md) — Ratchet 脚本模板check/baseline/report 三命令)
- [convention-script.md](templates/convention-script.md) — 约定检测脚本模板grep 模式匹配)
- [gates-doc.md](templates/gates-doc.md) — GATES.md 文档模板
- [pre-commit-config.md](templates/pre-commit-config.md) — husky + lint-staged 配置Node.js/Go/Monorepo
### 与需求级门禁的关系
```
Harness项目级护栏 req-test-gate需求级门禁
├── .husky/ pre-commit ├── Gate 0A: scope 分级
├── CI lint workflow ├── Gate 0B: 运行 harness 的 check-*.sh ←─ 连接点
├── scripts/check-*.sh ├── Gate 1: 前置条件
├── CLAUDE.md 约定 ├── Gate 2: 测试执行
│ ├── Gate 3: 质量验证
│ ├── Gate 4: 文档持久化
│ └── Gate 5: 回归贡献
```
> Harness 不使用 Gate 编号。它的产出物check-*.sh 脚本)通过 Gate 0B 接入 req-test-gate 流程。

View File

@@ -0,0 +1,222 @@
# Convention Flow — 约定建立流程
## 核心理念
**每个 bug 都是一个建立约定的机会。** 修复 bug 后,立即将教训固化为自动化检测,防止同类问题再次出现。
## 流程总览
```
Step 1: 修 Bug → 标准修复,代码层面解决问题
Step 2: 文档化约定 → 写入 CLAUDE.md让 AI 和人都知道这条规则)
Step 3: 自动化检测 → 创建 scripts/check-*.sh让 CI 自动阻止违规)
Step 4: 记录追踪 → 创建【约定】任务关联需求(仅 /req cr 自动触发时)
```
> Step 1-3 是核心流程手动和自动都执行。Step 4 仅在 `/req cr` 自动触发时执行,用于在 ai-proj 中留痕。
### Step 1: 修 Bug
标准的 bug 修复流程。此步骤无特殊要求。
### Step 2: 文档化约定
在项目的 CLAUDE.md 中添加约定段落,格式参见 [harness-engineering.md](harness-engineering.md) 的「CLAUDE.md 约定文档格式」。
**必须包含**
- 原因描述(为什么这是个问题)
- 一句话规则
- 正例和反例代码
- 检查命令
### Step 3: 自动化检测
创建 `scripts/check-{name}.sh` 脚本:
1. 扫描代码库查找违反约定的模式
2. 输出违规文件和行号
3. 支持 `--ci` 模式(退出码 0/1
4. 零违规时输出 PASSED 消息
### Step 4: 记录追踪(自动触发时)
当 convention flow 由 `/req cr` 自动触发时,产出物必须关联到当前需求:
```
ai-proj task create --title "【约定】{约定名称}"
ai-proj req link --id <req_id> --task-ids <task_id> # linkRole=documentation
ai-proj create-and-attach --id <task_id> --content "..." # 约定详情文档
```
**约定详情文档内容**
```markdown
## 约定: {名称}
| 字段 | 值 |
|------|-----|
| 来源需求 | REQ-XXXX |
| 触发 bug | {bug 描述} |
| 根因模式 | {代码模式} |
| 策略 | {hard wall / ratchet(N)} |
| 现有违规 | {N} 处 |
### 产出物
- CLAUDE.md 约定段落: ✅ 已添加
- 检测脚本: `scripts/check-{name}.sh` ✅ 已创建
- 首次运行结果: PASS
### 约定规则
{规则内容,与 CLAUDE.md 中一致}
```
> 这样在需求归档时能看到:这个 bug 不仅被修了,还产出了一条防止复发的约定。
## Commit 策略
Convention flow 的产出物CLAUDE.md 修改 + `scripts/check-*.sh` 新脚本)**必须单独提交**,不与 bug fix 代码混在一起:
```bash
# 1. Bug fix 已经提交
git add src/...
git commit -m "fix: 修复 Modal 重叠导致弹窗无法关闭"
# 2. Convention 产出物单独提交
git add CLAUDE.md scripts/check-modal-safety.sh
git commit -m "chore: 建立 Modal 安全约定和自动检测"
```
**原因**
- bug fix 可能需要 cherry-pick 到其他分支,约定脚本不应跟着走
- 约定提交的 review 焦点不同(规则是否合理 vs 代码是否正确)
- `git log --oneline scripts/` 可以快速看到所有约定建立历史
## 可检测性判断
`/req cr` 自动触发时AI 必须先判断 bug 根因是否能自动检测。判断标准:
**可检测(建议约定)** — 根因是一个**代码模式**,能用 grep/regex 在源码中匹配:
| 模式类别 | 示例 | grep 可行性 |
|---------|------|------------|
| API 误用 | `Modal.success()` 后直接 `setState` | grep `Modal.success` + 上下文检查 |
| 禁止导入 | handler 直接 import database 层 | grep import 路径 |
| 缺失守卫 | SQL 拼接而非参数化查询 | grep 字符串拼接模式 |
| 遗漏回调 | Promise 无 `.catch()` | grep `.then(` 无配对 `.catch` |
| 硬编码 | 密钥/密码直接写在代码中 | grep 常见密钥模式 |
**不可检测(仅记录根因)** — 根因是**逻辑/设计问题**,代码形态上看不出来:
| 模式类别 | 示例 | 为什么不行 |
|---------|------|-----------|
| 算法错误 | 排序方向反了、边界条件漏了 | 代码语法正确,逻辑错误 |
| 业务规则遗漏 | 退款应该校验订单状态但没校验 | 缺失的代码无法被 grep |
| 竞态条件 | 两个请求并发修改同一资源 | 需要运行时才能暴露 |
| 配置错误 | 环境变量填错、超时值设太小 | 值的正确性取决于上下文 |
**快速判断法**:问自己「能不能写一条 grep 命令找到所有同类问题?」能 → 可检测,不能 → 不可检测。
## 选择策略
修完 bug 后,根据当前违规数量选择不同策略:
| 现有违规数 | 策略 | 脚本类型 | 说明 |
|-----------|------|---------|------|
| **0** | Hard wall | 纯检测脚本(有 → FAIL | 刚修完最后一个违规,或首次建立 |
| **1-10** | Ratchet + 排期清理 | Ratchet 脚本 + 基线 | 创建任务逐一清理遗留 |
| **>10** | Ratchet only | Ratchet 脚本 + 基线 | 不立即清理,仅防止恶化 |
| **不可计数** | 仅检测/告警 | 告警脚本exit 0 | 如"代码风格"类软约定 |
## 实例 1: Modal 安全规则
**Bug**Ant Design `Modal.success()` 非阻塞,后续 `setState` 立即执行导致两个 modal 重叠,第一个无法关闭。
**Step 1 — 修 Bug**
`setNextModalOpen(true)` 移入 `onOk` 回调。
**Step 2 — 文档化**
在 CLAUDE.md 添加:
```markdown
### Frontend: Modal 安全规则
Ant Design 的 `Modal.success()` / `Modal.info()` 是**非阻塞**调用。
**规则:`Modal.success/info/warning/error` 之后如果还有 UI 操作,必须放在 `onOk` 回调中。**
// WRONG — 两个 modal 同时弹出
Modal.success({ title: '成功' });
setNextModalOpen(true);
// CORRECT — 等用户确认后再打开
Modal.success({ title: '成功', onOk: () => setNextModalOpen(true) });
**检查命令**`./scripts/check-modal-safety.sh`
```
**Step 3 — 自动化**
创建 `scripts/check-modal-safety.sh`
- 扫描 `.tsx` 文件中的 `Modal.success/info/warning/error` 调用
- 检查 25 行内是否有 `onOk` 回调
- 如果没有且后续 20 行内有 `set*Open(true)`,标记为违规
- 策略:现有违规 = 0 → Hard wall
## 实例 2: 架构层级约束
**问题**Handler 直接调用 database 层,绕过 service 层导致业务逻辑散落。
**Step 1 — 识别问题**
发现 108 个 handler 直接 import database 的文件。
**Step 2 — 文档化**
在 CLAUDE.md 和 `docs/architecture/LAYER_RULES.md` 中描述依赖矩阵和正反示例。
**Step 3 — 自动化**
创建 `scripts/check-architecture.sh`ratchet 脚本):
- 5 条规则3 个 ratchet + 2 个 hard wall
- 基线记录各规则的当前违规数
- 策略:遗留 108 个 → Ratchet只能减不能增
## 执行流程
### 自动触发(`/req cr` + bug 类需求)
**触发条件**(满足任一):
- `category == bug`
- category 为空但标题含 `fix``修复``bug``问题``缺陷`
- category 为空但 description 含 `根因``复现步骤`
```
1. /req cr 五视角扫描完成后
2. 检测是否为 bug 类需求(按上述条件判断)
3. 分析本次 bug 的根因模式(从 git diff 提取)
4. 判断:根因是否可自动检测?(判断规则见上方「可检测性判断」)
- 不可检测 → 仅在 CR 报告记录根因,不建议约定 → 结束
- 可检测 → 继续下一步
5. 检查是否已有覆盖此模式的脚本:
- ls scripts/check-*.sh读取每个脚本的注释头# ... detects ...
- 已有覆盖 → CR 报告记录「已有约定: check-{name}.sh」→ 结束
- 无覆盖 → 继续下一步
6. 扫描代码库统计同类模式的现有数量N
7. AskUserQuestion按 N 值调整措辞):
- N=0: 「此 bug 模式已修复,当前代码无同类问题。建立约定可防止未来复发,是否建立?」
- N>0: 「代码库中还有 {N} 处同类模式。建立约定可防止恶化 + 逐步清理,是否建立?」
- 否 → 记录到 CR 报告「约定建议:用户跳过」
- 是 → 执行 convention flowStep 2 + Step 3 + Step 4
8. 约定产出物关联到当前需求Step 4
9. 约定检查结果写入 CR 报告
```
### 手动触发(`/harness convention [name]`
```
1. 询问约定名称和类别(如果未提供)
2. 分析刚修复的 bug提取约定规则
3. 扫描代码库统计现有违规数量
4. 根据违规数量选择策略
5. 生成 CLAUDE.md 约定段落
6. 生成 scripts/check-{name}.sh 脚本
7. 运行脚本验证(应该 PASS
8. 输出摘要:约定名称、策略、违规数、文件清单
```

View File

@@ -0,0 +1,113 @@
# Harness Engineering — 工程约束方法论
## 概述
Harness Engineering 是一套**建立自动化护栏防止新违规,同时允许渐进式清理遗留问题**的工程方法论。
**三大支柱**
| 支柱 | 核心机制 | 说明 |
|------|---------|------|
| **Ratchet** | 基线 + 单调递减 | 遗留违规数只能减不能增,新代码零容忍 |
| **约定建立** | Bug → 文档 → 自动检测 | 每个 bug 修复后立即建立约定和检测脚本 |
| **门禁层级** | Level 1-3 递进 | 按项目成熟度逐级引入基础设施 |
## 子文件索引
| 文件 | 内容 |
|------|------|
| [ratchet-pattern.md](ratchet-pattern.md) | Ratchet 模式详解Ratchet vs Hard Wall、基线格式、三命令接口 |
| [convention-flow.md](convention-flow.md) | 三步约定建立流程:修 bug → 文档化 → 自动化检测 |
| [project-bootstrap.md](project-bootstrap.md) | `/harness assess` 检测逻辑 + `/harness init` 分级实施指南 |
| [templates/](templates/) | 脚本模板ratchet、约定检测、GATES.md、pre-commit 配置 |
## 命令集与自动触发
| 命令 | 手动触发 | 自动触发时机 |
|------|---------|-------------|
| `/harness assess` | 用户显式调用 | **`/req dev`** 启动时快速检测(`.husky/` + `scripts/check-*.sh` 都不存在 → 提示 Level 0 |
| `/harness init [level]` | 用户显式调用 | 不自动触发(创建基础设施需用户确认) |
| `/harness convention [name]` | 用户显式调用 | **`/req cr` + category=bug** 时自动建议(分析根因 → 建议约定 → 用户确认后执行) |
| `/harness report` | 用户显式调用 | **`/req test` Gate 0B** 自动运行所有 `scripts/check-*.sh` |
### 自动触发流程图
```
/req dev (每次)
└→ 快速检测: .husky/ 存在? scripts/check-*.sh 存在?
└→ 都不存在 → 提示「Level 0建议 /harness init」不阻塞
└→ 有任一 → 静默通过
/req cr (bug 类型需求)
└→ 五视角扫描
└→ 运行 scripts/check-*.sh → 写入 CR 报告
└→ ⭐ 分析 bug 根因 → 可自动检测? → 建议建立约定
└→ 用户确认 → convention flow文档化 → 脚本 → CLAUDE.md
/req test
└→ Gate 0A: scope 分级
└→ Gate 0B: 运行所有 scripts/check-*.sh
└→ 有 FAIL → 阻塞,必须修复
└→ 全 PASS → 继续 Gate 1-5
```
> 手动命令仍然可用。自动触发只是让你"不用记得去跑"。
## 成熟度分级
| Level | 基础设施 | 适用场景 |
|-------|---------|---------|
| **0** | 无自动化检查 | 新项目/原型 |
| **1** | husky + lint-staged + formatter | 所有活跃项目 |
| **2** | + ratchet 脚本 + GATES.md + CLAUDE.md 质量段落 | >10k LOC 或 >1 开发者 |
| **3** | + CI workflow + 架构强制 + 约定检测 | 有 PR 流程和受保护分支的项目 |
## 技术栈检测矩阵
| 技术栈 | 检测标志 | Level 1 工具 | Level 2+ 工具 |
|--------|---------|-------------|--------------|
| **Go** | `go.mod` | gofmt + go vet | golangci-lint, architecture ratchet |
| **React/TS** | `package.json` + react 依赖 | ESLint + Prettier | tsc --noEmit, convention scripts |
| **Vue/TS** | `package.json` + vue 依赖 | ESLint + Prettier | vite build check |
| **Monorepo** | 多个 `package.json` / `go.mod` | 各子项目独立 lint | 统一 CI + 分模块 ratchet |
## CLAUDE.md 约定文档格式
在项目的 CLAUDE.md 中添加约定时,必须遵循以下标准格式:
```markdown
### {类别}: {约定名称}
{原因描述 — 为什么需要这条约定}
**规则:{一句话规则描述}**
\`\`\`{语言}
// WRONG — {错误原因}
{错误代码示例}
// CORRECT — {正确做法}
{正确代码示例}
\`\`\`
**检查命令**`./scripts/check-{name}.sh`CI 自动运行)
```
## 与其他技能的关系
Harness 和 req-test-gate 是**互补关系**,不要混淆两者的 Gate 编号:
| 维度 | Harness | req-test-gate |
|------|---------|--------------|
| **作用域** | 项目级(所有 PR 共享) | 需求级(每个需求独立) |
| **触发方式** | git commit / PR / `/req test` Gate 0B | `/req test` Gate 1-5 |
| **管什么** | pre-commit、lint、ratchet 脚本、约定检测 | 测试执行、质量验证、文档持久化、回归 |
| **产出物** | `.husky/``scripts/check-*.sh`、CLAUDE.md 约定 | 测试报告、回归用例 |
**⚠️ 注意**:项目的 `docs/quality/GATES.md` 中有自己的 Gate 编号Gate 0=pre-commit, Gate 1=CI lint, Gate 2=ratchet...),这是**项目文档的编号**,与 req-test-gate 的 Gate 0-5 是两套独立体系,不要混用。
| 技能 | 职责 |
|------|------|
| **harness**(本文档) | 建立和维护项目级护栏脚本、约定、CLAUDE.md |
| **req-test-gate** | 需求级测试门禁Gate 0-5其中 Gate 0B 自动调用 harness 建立的脚本 |
| **dev-coding** | 遵守 harness 建立的 CLAUDE.md 约定,编码时不违反 ratchet |

View File

@@ -0,0 +1,194 @@
# Project Bootstrap — 工程约束基础设施引导
## `/harness assess` 检测逻辑
扫描项目结构自动判断成熟度等级0-3列出缺口和建议。
### 检测项清单(每项附实际执行的命令)
| 检测项 | 执行命令 | 判定 | Level |
|--------|---------|------|-------|
| 技术栈 | `Glob("package.json", "go.mod", "Podfile", "*.csproj")` | 存在即识别 | 基础 |
| Pre-commit hooks | `Glob(".husky/pre-commit")` | 文件存在 | 1 |
| Lint 配置 | `Glob(".eslintrc*", ".golangci.yml") + Grep("lint", "Makefile")` | 任一存在 | 1 |
| Formatter | `Glob(".prettierrc*") + Grep("gofmt\\|prettier", ".husky/pre-commit")` | 任一存在 | 1 |
| lint-staged | `Grep("lint-staged", "package.json") + Glob(".lintstagedrc*")` | 任一存在 | 1 |
| 约定脚本 | `Glob("scripts/check-*.sh")` | 至少 1 个 | 2 |
| 基线文件 | `Glob("scripts/.*-baseline.json")` | 至少 1 个 | 2 |
| 门禁文档 | `Glob("docs/quality/GATES.md")` | 文件存在 | 2 |
| CLAUDE.md 质量段落 | `Grep("检查命令\\|check-.*\\.sh", "CLAUDE.md")` | 有匹配 | 2 |
| CI workflow | `Grep("check-.*\\.sh", ".gitea/workflows/*.yml", ".github/workflows/*.yml")` | 有匹配 | 3 |
### 等级判定
```
Level 0: 无上述任何基础设施
Level 1: 有 pre-commit hooks + lint + formatter
Level 2: Level 1 + 有 ratchet/约定脚本 + GATES.md
Level 3: Level 2 + CI 自动运行 + 受保护分支
```
### 输出格式
```markdown
## Harness Assessment: {项目名}
**技术栈**: Go + React (monorepo)
**当前等级**: Level 2
### 已有基础设施
- [x] husky pre-commit hooks
- [x] ESLint + Prettier (frontend)
- [x] gofmt + go vet (backend)
- [x] check-architecture.sh (ratchet, 5 rules)
- [x] check-modal-safety.sh (hard wall)
- [x] GATES.md
### 缺口(升至 Level 3
- [ ] CI workflow 未调用 check-architecture.sh
- [ ] CI workflow 未调用 check-modal-safety.sh
### 建议
1. 在 .gitea/workflows/quality-gates.yaml 中添加 check-architecture.sh check
2. 在 .gitea/workflows/quality-gates.yaml 中添加 check-modal-safety.sh --ci
```
---
## `/harness init [level]` 分级实施
### Level 1: 基础代码格式化
**适用**:所有活跃项目。
#### Node.js 项目
```bash
# 1. 安装 husky + lint-staged
npm install -D husky lint-staged
npx husky init
# 2. 配置 lint-stagedpackage.json
# 参见 templates/pre-commit-config.md — Node.js 变体
# 3. 配置 pre-commit hook
echo "npx lint-staged" > .husky/pre-commit
```
#### Go 项目
```bash
# 1. 安装 husky需要 package.json
npm init -y
npm install -D husky lint-staged
npx husky init
# 2. 配置 lint-stagedpackage.json
# 参见 templates/pre-commit-config.md — Go 变体
# 3. 配置 pre-commit hook
echo "npx lint-staged" > .husky/pre-commit
```
#### Monorepo
```bash
# 根目录安装 husky各子项目配置 lint-staged
# 参见 templates/pre-commit-config.md — Monorepo 变体
```
### Level 2: 约定与 Ratchet
**前置**Level 1 已完成。
#### Step 1: 创建目录结构
```bash
mkdir -p scripts docs/quality
```
#### Step 2: 创建 GATES.md
参见 [templates/gates-doc.md](templates/gates-doc.md),填入项目实际的 lint 工具和 CI 系统。
#### Step 3: 约束发现(关键步骤)
AI 必须探索项目代码库,按以下清单逐项检查,找出适合建 ratchet 的约束:
| 检查项 | 检测方法 | 发现约束时 |
|--------|---------|-----------|
| **分层架构** | 读 `go.mod` / 目录结构,判断是否有 handler/service/repository 分层 | 检查跨层 import → ratchet |
| **禁止 import** | `grep -r "import" --include="*.go"` 找不应出现的包引用 | 统计违规数 → ratchet 或 wall |
| **前端 API 调用规范** | `grep -r "fetch\|axios" --include="*.tsx"` 看是否有直接调用(应走 service 层) | 统计违规数 → ratchet |
| **console.log 残留** | `grep -r "console.log" --include="*.tsx" --include="*.ts"` | 统计数量 → ratchet |
| **硬编码配置** | `grep -rn "localhost\|127.0.0.1\|:3000\|:8080" --include="*.ts" --include="*.go"` 排除测试和配置文件 | 统计数量 → ratchet |
| **TODO/FIXME** | `grep -rn "TODO\|FIXME" --include="*.go" --include="*.ts"` | 统计数量 → ratchet仅追踪不阻塞 |
**执行流程**
```
1. 读取项目目录结构ls -R 前两层)
2. 识别技术栈和架构风格
3. 按上表逐项 grep 扫描
4. 筛选:违规数 > 0 的项列为候选规则
5. AskUserQuestion展示候选规则表让用户勾选要建哪些
6. 对每条选中的规则:
a. 用 ratchet-script 模板生成 scripts/check-{name}.sh
b. 运行 baseline 记录初始值
c. 在 CLAUDE.md 添加约定段落
```
> 如果扫描后没有发现任何候选规则代码量很小或结构简单Level 2 只创建 GATES.md + CLAUDE.md 质量段落,不创建 ratchet 脚本。后续通过 convention flow修 bug 时)逐步积累。
#### Step 4: CLAUDE.md 质量段落
参见 [harness-engineering.md](harness-engineering.md) 的「CLAUDE.md 约定文档格式」。
#### Step 5: 提交
```bash
./scripts/check-{name}.sh baseline # 每个新脚本都要 baseline
git add scripts/ docs/quality/ CLAUDE.md
git commit -m "chore: establish harness engineering Level 2"
```
### Level 3: CI 强制
**前置**Level 2 已完成 + 项目有 CI 和受保护分支。
```yaml
# .gitea/workflows/quality-gates.yaml 示例
name: Quality Gates
on:
pull_request:
branches: [main, develop]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Architecture Check
run: ./scripts/check-architecture.sh check
- name: Convention Checks
run: |
for script in scripts/check-*.sh; do
[ "$script" = "scripts/check-architecture.sh" ] && continue
bash "$script" --ci
done
```
---
## `/harness init` 执行流程
```
1. 运行 /harness assess 确定当前等级
2. 确定目标等级(用户指定或默认 Level 1
3. 如果当前等级 ≥ 目标等级,提示"已满足"
4. 按目标等级模板生成文件:
- Level 1: .husky/ + package.json lint-staged
- Level 2: scripts/ + docs/quality/ + CLAUDE.md 段落
- Level 3: CI workflow
5. 运行验证husky hook 是否生效、脚本是否可执行)
6. 输出文件清单和下一步建议
```

View File

@@ -0,0 +1,96 @@
# Ratchet Pattern — 渐进式违规清理
## Ratchet vs Hard Wall
| 策略 | 适用场景 | 基线值 | CI 行为 |
|------|---------|--------|---------|
| **Ratchet** | 有遗留违规(>0 | 当前违规数 | 新值 > 基线 → FAIL |
| **Hard Wall** | 必须为零 | 固定 = 0 | 值 ≠ 0 → FAIL |
**选择依据**
- 遗留违规 = 0 → Hard Wall绝对禁止
- 遗留违规 > 0 → Ratchet允许存在但不能增加
## 基线文件格式
基线以 JSON 格式存储,提交到 git
```json
{
"rule_name_1": 108,
"rule_name_2": 7,
"rule_name_3": 0
}
```
**位置约定**`scripts/.{检测名}-baseline.json`(如 `scripts/.architecture-baseline.json`
## 三命令接口
每个 ratchet 脚本必须实现三个子命令:
| 命令 | 用途 | CI 使用 |
|------|------|---------|
| `check` | 比较当前值与基线,增加则失败 | PR 门禁 |
| `baseline` | 记录当前值为新基线 | 修复违规后手动执行 |
| `report` | 打印当前值 vs 基线的对比表 | 人工审查 |
```bash
./scripts/check-{name}.sh check # CI: fail if violations increased
./scripts/check-{name}.sh baseline # After fix: record new lower baseline
./scripts/check-{name}.sh report # Human: see current vs baseline
```
## 何时降低基线
```
1. 修复一个或多个违规
2. 运行 check → PASS因为当前值 ≤ 旧基线)
3. 运行 baseline → 记录更低的基线
4. git commit 新的基线文件
5. 后续 PR 使用更低的基线
```
**关键**:修复后一定要 `baseline` + commit否则下次有人新增违规会被允许因为基线还是旧的高值
## 多规则 Ratchet
一个脚本可以管理多条规则每条规则有独立的基线值和类型ratchet/wall
```bash
# rules 数组定义规则名
rules=("handlers_import_database" "routes_import_database" "models_import_upper")
# types 数组定义策略
types=("ratchet" "ratchet" "wall")
# 循环检查每条规则
for i in "${!rules[@]}"; do
rule="${rules[$i]}"
type="${types[$i]}"
# ...
done
```
## 参考实现
**new-ai-proj** 项目的架构 ratchet
- 脚本:`scripts/check-architecture.sh`
- 基线:`scripts/.architecture-baseline.json`
- 规则文档:`docs/architecture/LAYER_RULES.md`
- 门禁文档:`docs/quality/GATES.md`
五条规则:
| 规则 | 类型 | 含义 |
|------|------|------|
| `handlers_import_database` | ratchet | Handler 不应直接访问数据库层 |
| `routes_import_database` | ratchet | 路由不应直接访问数据库层 |
| `routes_import_services` | ratchet | 路由应通过 handler 委托 |
| `models_import_upper` | hard wall | 模型层禁止反向依赖 |
| `services_import_handlers` | hard wall | 服务层禁止反向依赖 |
## 设计 Ratchet 规则的原则
1. **可计数** — 规则违规必须能通过 grep/AST 精确计数
2. **无歧义** — 一个文件/行要么违规要么不违规,不能有灰色地带
3. **可修复** — 开发者必须知道怎么把违规改正确
4. **有文档** — 每条规则配 LAYER_RULES.md 或 CLAUDE.md 中的正反示例

View File

@@ -0,0 +1,120 @@
# Convention Detection Script Template
泛化的约定检测脚本模板,基于 new-ai-proj `check-modal-safety.sh` 提取。用于检测代码中违反编码约定的模式。
## 使用方法
1. 复制下方脚本到 `scripts/check-{NAME}.sh`
2. 替换所有 `{PLACEHOLDER}` 为项目特定值
3. 运行 `chmod +x scripts/check-{NAME}.sh`
4. 验证:`./scripts/check-{NAME}.sh` 输出 PASSED
## 脚本模板
```bash
#!/usr/bin/env bash
#
# {CONVENTION_NAME} Check — detects {WHAT_IT_DETECTS} in {TARGET_SCOPE}.
#
# {PROBLEM_DESCRIPTION}
#
# Usage:
# ./scripts/check-{NAME}.sh # Check and report
# ./scripts/check-{NAME}.sh --ci # Exit code 1 on violations
#
set -euo pipefail
TARGET_DIR="$(cd "$(dirname "$0")/../{TARGET_DIRECTORY}" && pwd)"
CI_MODE=false
[[ "${1:-}" == "--ci" ]] && CI_MODE=true
violations=0
# ── detection logic ─────────────────────────────────────────────────
# Strategy A: Simple grep pattern (file-level)
# Find files matching a bad pattern, optionally excluding false positives.
#
# while IFS= read -r file; do
# rel_path="${file#"$TARGET_DIR"/}"
# echo "WARNING: $rel_path — {VIOLATION_MESSAGE}"
# violations=$((violations + 1))
# done < <(grep -rl '{BAD_PATTERN}' "$TARGET_DIR" --include='{FILE_GLOB}' 2>/dev/null \
# | while read f; do grep -L '{FALSE_POSITIVE_PATTERN}' "$f" 2>/dev/null; done)
# Strategy B: Line-level with context (multi-condition)
# Find a primary pattern, check nearby lines for secondary pattern.
#
# while IFS= read -r file; do
# while IFS= read -r line_num; do
# # Check context around the match
# has_mitigation=$(sed -n "${line_num},$((line_num + {CONTEXT_LINES}))p" "$file" \
# | grep -c '{MITIGATION_PATTERN}' || true)
# if [[ "$has_mitigation" -eq 0 ]]; then
# # Additional condition: check if problematic follow-up exists
# after_end=$((line_num + {LOOKAHEAD_LINES}))
# has_problem=$(sed -n "$((line_num + 1)),${after_end}p" "$file" \
# | grep -cE '{FOLLOW_UP_BAD_PATTERN}' || true)
# if [[ "$has_problem" -gt 0 ]]; then
# rel_path="${file#"$TARGET_DIR"/}"
# echo "WARNING: $rel_path:$line_num — {VIOLATION_MESSAGE}"
# violations=$((violations + 1))
# fi
# fi
# done < <(grep -n '{PRIMARY_PATTERN}' "$file" | cut -d: -f1)
# done < <(grep -rl '{PRIMARY_PATTERN}' "$TARGET_DIR" --include='{FILE_GLOB}' 2>/dev/null)
# ── results ─────────────────────────────────────────────────────────
if [[ "$violations" -gt 0 ]]; then
echo ""
echo "Found $violations {CONVENTION_NAME} violation(s)."
echo "Fix: {FIX_GUIDANCE}"
echo "Docs: see CLAUDE.md '{CLAUDE_MD_SECTION}'"
$CI_MODE && exit 1
else
echo "{CONVENTION_NAME} check PASSED."
fi
```
## Placeholder 说明
| Placeholder | 含义 | 示例 |
|-------------|------|------|
| `{NAME}` | 脚本短名 | `modal-safety`, `sql-injection` |
| `{CONVENTION_NAME}` | 约定显示名 | `Modal safety`, `SQL injection prevention` |
| `{WHAT_IT_DETECTS}` | 检测内容 | `potential modal overlap patterns` |
| `{TARGET_SCOPE}` | 目标范围描述 | `frontend code`, `Go handlers` |
| `{TARGET_DIRECTORY}` | 扫描目录 | `frontend/src`, `backend` |
| `{PROBLEM_DESCRIPTION}` | 问题描述 | `Ant Design Modal.success is non-blocking...` |
| `{FILE_GLOB}` | 文件匹配 | `*.tsx`, `*.go` |
| `{PRIMARY_PATTERN}` | 主匹配模式 | `Modal\.\(success\|info\)` |
| `{MITIGATION_PATTERN}` | 缓解模式(有则排除) | `onOk` |
| `{FOLLOW_UP_BAD_PATTERN}` | 后续违规模式 | `set\w*Open\(true\)` |
| `{CONTEXT_LINES}` | 上下文行数 | `25` |
| `{LOOKAHEAD_LINES}` | 前瞻行数 | `20` |
| `{BAD_PATTERN}` | Strategy A 主匹配模式 | `console\.log` |
| `{FALSE_POSITIVE_PATTERN}` | Strategy A 排除模式(匹配到则非违规) | `// eslint-disable` |
| `{VIOLATION_MESSAGE}` | 违规消息 | `Modal without onOk followed by setState` |
| `{FIX_GUIDANCE}` | 修复指导 | `add onOk callback to Modal` |
| `{CLAUDE_MD_SECTION}` | CLAUDE.md 章节名 | `Frontend: Modal 安全规则` |
## 两种检测策略
### Strategy A: 文件级检测
适用于:整个文件不应出现某模式(或出现即违规)。
例子:
- `console.log` 在生产代码中
- `TODO` / `FIXME` 计数
- 缺少 license header
### Strategy B: 行级 + 上下文检测
适用于:模式本身不违规,需要检查周围上下文。
例子:
- `Modal.success()` 不违规,但后面紧跟 `setState` 才违规
- `db.Exec()` 不违规,但参数用字符串拼接才违规
- `fmt.Println()` 不违规,但在 handler 中输出敏感数据才违规

View File

@@ -0,0 +1,102 @@
# GATES.md Template
项目质量门禁文档模板。放置于 `docs/quality/GATES.md`
## 使用方法
1. 复制下方模板到项目的 `docs/quality/GATES.md`
2. 替换 `{PLACEHOLDER}` 为项目特定值
3. 根据项目实际情况增删 Gate
## 模板
```markdown
# Quality Gates
Quality gates are automated checks that code must pass before it can be merged or deployed.
## Gate Overview
| Gate | Name | Where | What it catches |
|------|------|-------|-----------------|
| 0 | Pre-commit | Local (husky) | Formatting, lint errors |
| 1 | CI Lint | {CI_SYSTEM} | {LINT_TOOLS} |
| 2 | Convention & Architecture | {CI_SYSTEM} | New violations of established rules |
| 3 | Unit Tests | CI / local | Logic bugs, regressions |
| 4 | Security Scan | CI | Dependency vulnerabilities |
| 5 | Build | CI | Compilation errors |
## Gate 0: Pre-commit (Local)
Runs automatically on every `git commit` via husky + lint-staged.
{FRONTEND_SECTION — include if applicable}
**Frontend** (`{FRONTEND_GLOBS}`):
- {LINT_TOOL} with {LINT_FLAGS}
- {FORMATTER}
{BACKEND_SECTION — include if applicable}
**Backend** (`{BACKEND_GLOBS}`):
- {FORMAT_TOOL} (auto-format)
- {ANALYSIS_TOOL} (static analysis)
**Bypass** (emergency only): `git commit --no-verify`
## Gate 1: CI Lint
Runs on pull requests via {CI_SYSTEM}.
- **Backend**: {BACKEND_LINT_COMMANDS}
- **Frontend**: {FRONTEND_LINT_COMMANDS}
## Gate 2: Convention & Architecture Checks
Runs on pull requests via {CI_SYSTEM}.
{LIST_EACH_CHECK_SCRIPT}
- `./scripts/check-{name}.sh check` — {description}
See project CLAUDE.md and docs/architecture/ for rule details.
## Gates 3-5: Testing, Security, Build
These gates are enforced via the `/req test` workflow:
1. **Gate 3**: Unit test generation and execution
2. **Gate 4**: Security regression scan
3. **Gate 5**: E2E smoke test + final report
See the dev-test skill documentation for details.
## Local Commands
\`\`\`bash
# Gate 0: Format & Lint
{LOCAL_LINT_COMMANDS}
# Gate 2: Convention checks
{LOCAL_CHECK_COMMANDS}
# Gate 3: Unit tests
{LOCAL_TEST_COMMANDS}
\`\`\`
```
## Placeholder 说明
| Placeholder | 含义 | 示例 |
|-------------|------|------|
| `{CI_SYSTEM}` | CI 系统名称 | `Gitea Actions`, `GitHub Actions` |
| `{LINT_TOOLS}` | lint 工具列表 | `golangci-lint, ESLint, TypeScript errors` |
| `{FRONTEND_GLOBS}` | 前端文件 glob | `*.ts, *.tsx`, `*.vue` |
| `{BACKEND_GLOBS}` | 后端文件 glob | `*.go` |
| `{LINT_TOOL}` | lint 工具 | `ESLint` |
| `{LINT_FLAGS}` | lint 参数 | `--fix --max-warnings 0` |
| `{FORMATTER}` | 格式化工具 | `Prettier`, `gofmt` |
## 注意事项
- **此文档的 Gate 编号是项目级的**(描述项目基础设施层级),与 req-test-gate 技能的 Gate 0-5需求级测试门禁是两套独立体系
- Gate 0-2 由 harness engineering 方法论管理pre-commit → CI lint → ratchet/约定检测)
- Gate 3-5 由 `/req test` 流程管理(单元测试 → 安全扫描 → 构建验证)
- 两者互补,不要混淆编号

View File

@@ -0,0 +1,135 @@
# Pre-commit Configuration Template
husky + lint-staged 配置模板三种变体Node.js 项目、Go 项目、Monorepo。
---
## 变体 1: Node.js 项目React / Vue / 纯 TS
### 安装
```bash
npm install -D husky lint-staged prettier eslint
npx husky init
echo "npx lint-staged" > .husky/pre-commit
```
### package.json
```json
{
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix --max-warnings 0",
"prettier --write"
],
"*.{css,less,scss}": [
"prettier --write"
],
"*.{json,md}": [
"prettier --write"
]
}
}
```
---
## 变体 2: Go 项目
### 安装
```bash
# Go 项目需要 package.json 来驱动 husky
npm init -y
npm install -D husky lint-staged
npx husky init
echo "npx lint-staged" > .husky/pre-commit
```
### package.json
```json
{
"lint-staged": {
"*.go": [
"gofmt -s -w",
"bash -c 'go vet ./...'"
]
}
}
```
### 可选golangci-lint更严格
```json
{
"lint-staged": {
"*.go": [
"gofmt -s -w",
"bash -c 'go vet ./...'",
"bash -c 'golangci-lint run --fix'"
]
}
}
```
---
## 变体 3: MonorepoGo + Node.js
### 安装(根目录)
```bash
npm install -D husky lint-staged
npx husky init
echo "npx lint-staged" > .husky/pre-commit
```
### package.json根目录
```json
{
"lint-staged": {
"frontend/**/*.{ts,tsx}": [
"bash -c 'cd frontend && npx eslint --fix --max-warnings 0'",
"bash -c 'cd frontend && npx prettier --write'"
],
"frontend/**/*.{css,less,json}": [
"bash -c 'cd frontend && npx prettier --write'"
],
"backend/**/*.go": [
"gofmt -s -w",
"bash -c 'cd backend && go vet ./...'"
]
}
}
```
### 注意事项
- `bash -c 'cd xxx && ...'` 确保命令在正确的子目录中执行
- lint-staged 传递的文件路径是相对于根目录的,部分工具(如 `go vet`)需要在子目录执行
- 如果前端和后端各自有 `package.json`lint-staged 仍然在根目录配置
---
## 验证配置
```bash
# 修改一个文件后测试 pre-commit hook
echo "// test" >> some-file.ts
git add some-file.ts
git commit -m "test: verify pre-commit hook"
# 应该看到 lint-staged 执行 ESLint + Prettier
# 如果有 lint 错误commit 会被阻止
```
## 常见问题
| 问题 | 原因 | 解决 |
|------|------|------|
| lint-staged 不执行 | `.husky/pre-commit` 内容不对 | 确认内容为 `npx lint-staged` |
| ESLint 报错太多 | 旧项目首次启用 | 先 `npx eslint --fix` 全量修复,再启用 hook |
| gofmt 修改后 commit 内容不一致 | lint-staged 自动 format 后需要 re-stage | lint-staged 自动处理,无需手动 |
| Monorepo 路径错误 | lint-staged 传递根目录相对路径 | 使用 `bash -c 'cd sub && ...'` 包装 |

View File

@@ -0,0 +1,189 @@
# Ratchet Script Template
泛化的 ratchet 脚本模板,基于 new-ai-proj `check-architecture.sh` 提取。
## 使用方法
1. 复制下方脚本到 `scripts/check-{NAME}.sh`
2. 替换所有 `{PLACEHOLDER}` 为项目特定值
3. 运行 `chmod +x scripts/check-{NAME}.sh`
4. 运行 `./scripts/check-{NAME}.sh baseline` 记录首次基线
5. 提交脚本和基线文件
## 脚本模板
```bash
#!/usr/bin/env bash
#
# {DESCRIPTION} Ratchet — ensures new code doesn't increase {WHAT} violations.
#
# Usage:
# ./scripts/check-{NAME}.sh check # CI / pre-push: fail if violations increased
# ./scripts/check-{NAME}.sh baseline # Record current counts (commit the result)
# ./scripts/check-{NAME}.sh report # Pretty-print current vs baseline
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
BASELINE_FILE="$SCRIPT_DIR/.{NAME}-baseline.json"
TARGET_DIR="$SCRIPT_DIR/../{TARGET_DIRECTORY}"
# ── rule definitions ────────────────────────────────────────────────
# Add/remove rules as needed. Each rule has:
# - A name (used as JSON key)
# - A type: "ratchet" (baseline can decrease) or "wall" (must be 0)
# - A count function
RULES=({RULE_NAMES}) # e.g. ("rule_one" "rule_two" "rule_three")
TYPES=({RULE_TYPES}) # e.g. ("ratchet" "ratchet" "wall")
# ── counting functions ──────────────────────────────────────────────
count_rule() {
local rule="$1"
case "$rule" in
{RULE_NAME_1})
# Example: count files in {DIR} that import {PACKAGE}
grep -rl '{PATTERN_1}' "$TARGET_DIR/{SUBDIR_1}/" 2>/dev/null | wc -l | tr -d ' '
;;
{RULE_NAME_2})
grep -rl '{PATTERN_2}' "$TARGET_DIR/{SUBDIR_2}/" 2>/dev/null | wc -l | tr -d ' '
;;
# Add more rules...
*)
echo "0"
;;
esac
}
# ── helpers ─────────────────────────────────────────────────────────
current_counts() {
echo "{"
local first=true
for rule in "${RULES[@]}"; do
local count
count=$(count_rule "$rule")
$first || echo ","
printf ' "%s": %s' "$rule" "${count:-0}"
first=false
done
echo ""
echo "}"
}
json_val() {
local key="$1" file="$2"
grep "\"${key}\"" "$file" | head -1 | sed 's/[^0-9]//g'
}
json_val_str() {
local key="$1" json="$2"
echo "$json" | grep "\"${key}\"" | head -1 | sed 's/[^0-9]//g'
}
# ── commands ────────────────────────────────────────────────────────
cmd_baseline() {
echo "Recording {NAME} baseline..."
current_counts > "$BASELINE_FILE"
echo "Baseline written to $BASELINE_FILE"
cat "$BASELINE_FILE"
}
cmd_report() {
if [[ ! -f "$BASELINE_FILE" ]]; then
echo "No baseline found. Run: $0 baseline"
exit 1
fi
local current
current=$(current_counts)
printf "\n%-35s %10s %10s %8s\n" "Rule" "Baseline" "Current" "Status"
printf "%-35s %10s %10s %8s\n" "---" "---" "---" "---"
for i in "${!RULES[@]}"; do
local rule="${RULES[$i]}"
local type="${TYPES[$i]}"
local base cur status
base=$(json_val "$rule" "$BASELINE_FILE")
cur=$(json_val_str "$rule" "$current")
if [[ "$type" == "wall" ]]; then
[[ "$cur" -eq 0 ]] && status="PASS" || status="FAIL"
else
[[ "$cur" -le "$base" ]] && status="PASS" || status="FAIL"
fi
printf "%-35s %10d %10d %8s\n" "$rule" "$base" "$cur" "$status"
done
echo ""
}
cmd_check() {
if [[ ! -f "$BASELINE_FILE" ]]; then
echo "ERROR: No baseline found. Run: $0 baseline"
exit 1
fi
local current
current=$(current_counts)
local failed=0
for i in "${!RULES[@]}"; do
local rule="${RULES[$i]}"
local type="${TYPES[$i]}"
local base cur
base=$(json_val "$rule" "$BASELINE_FILE")
cur=$(json_val_str "$rule" "$current")
if [[ "$type" == "wall" ]]; then
if [[ "$cur" -ne 0 ]]; then
echo "FAIL [hard wall] $rule: expected 0, got $cur"
failed=1
fi
else
if [[ "$cur" -gt "$base" ]]; then
echo "FAIL [ratchet] $rule: baseline=$base, current=$cur (+$((cur - base)))"
failed=1
fi
fi
done
if [[ "$failed" -eq 1 ]]; then
echo ""
echo "{NAME} check FAILED. New violations detected."
echo "If this is intentional, update the baseline: $0 baseline"
exit 1
fi
echo "{NAME} check PASSED."
}
# ── main ────────────────────────────────────────────────────────────
case "${1:-check}" in
baseline) cmd_baseline ;;
report) cmd_report ;;
check) cmd_check ;;
*)
echo "Usage: $0 {check|baseline|report}"
exit 1
;;
esac
```
## Placeholder 说明
| Placeholder | 含义 | 示例 |
|-------------|------|------|
| `{NAME}` | 脚本短名 | `architecture`, `import-rules` |
| `{DESCRIPTION}` | 一句话描述 | `Architecture`, `Import Boundary` |
| `{TARGET_DIRECTORY}` | 扫描目标目录(相对于 scripts/ | `backend`, `frontend/src` |
| `{RULE_NAMES}` | Bash 数组,规则名列表 | `"handler_db" "route_db"` |
| `{RULE_TYPES}` | Bash 数组,规则类型列表 | `"ratchet" "wall"` |
| `{PATTERN_N}` | grep 匹配模式 | `"my-pkg/database"` |
| `{SUBDIR_N}` | 目标子目录 | `handlers/`, `routes/` |

View File

@@ -0,0 +1,8 @@
{
"name": "req-workflow-plugin",
"description": "需求完整工作流。从创建到归档的完整流程、Hook 自动同步、测试环境流程。",
"version": "1.0.0",
"author": {
"name": "qiudl"
}
}

View File

@@ -0,0 +1,208 @@
---
name: req-workflow
description: 需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。
---
# 需求完整工作流
从 PRD 到归档的完整流程。
## 完整流程概览(阶段化)
```
1. /req new → 创建需求 (draft)
2. req-prd 技能 → 编写 PRD创建【评审】PRD 任务)
2.5 /req prototype → 生成 Stitch 原型(可选,有 UI 时推荐)
3. /req review → 提交评审 (pending)
4. /req review pass → 评审通过 (approved, delivery_stage=analysis)
5. /req next → 推进到 design/dev 阶段
6. /req dev → 启动开发(创建【开发】任务, delivery_stage=dev
7. req-design 技能 → 编写开发设计文档
7.5 /req ci → CI 质量门禁检查与自动修复PR 提交后执行)
8. /req next → 推进到 review需 quality_gate 门禁证据)
9. /req cr → 代码评审(创建【代码评审】任务, delivery_stage=review
10. /req next → 推进到 testing 阶段
11. /req test → 测试验收(创建【测试】任务, delivery_stage=testing
12. /req next → 推进到 staging 阶段
13. /req deploy staging → 部署 staging创建【部署】任务, delivery_stage=staging
14. /req next → 推进到 released 阶段
15. /req deploy prod → 部署生产 + PDV 验收(健康检查 → E2E 验收 → released
16. /req done → 归档 (archived)
```
**每个阶段都有明确的任务、检查点和交付物,防止遗漏。**
## 5 阶段文档
| 阶段 | 文档名 | 技能 |
|------|--------|------|
| PRD | 01-PRD.md | `req-prd` |
| 开发 | 02-开发设计.md | `req-design` |
| 测试 | 03-测试报告.md | 自动生成 |
| 发布 | 04-发布记录.md | 自动生成(含 PDV 验收章节) |
| 归档 | 05-生命周期总结.md | 自动生成 |
> Stitch 原型不单独编号,嵌入 01-PRD.md 的「4.2 界面原型」章节。
## Hook 自动同步
需求操作自动触发同步,无需手动执行:
| 事件 | 触发操作 |
|------|----------|
| `requirement.created` | 同步到远程 |
| `requirement.approved` | 同步需求和任务 |
| `task.completed` | 同步任务状态 |
| `requirement.archived` | 最终同步 + 思源笔记 |
**手动同步**(如需):
```typescript
mcp__ai-proj__sync_requirement_to_remote(requirementId)
mcp__ai-proj__batch_sync_tasks_to_remote(taskIds)
```
## 测试环境流程
**必须按顺序执行,任何阶段失败后从本机重新开始**
```
[本机] → 通过 → [预发布] → 通过 → [生产]
↑ │ │
└─────────────────┴──── 失败 ────┘
```
| 环境 | 用途 | 验证方式 |
|------|------|----------|
| 本机 | 开发调试 | `go test ./...` |
| 预发布 | 集成测试 | API 验证 |
| 生产 | 最终验收 | 健康检查 + PDV E2E 验收页面可达、菜单可见、API 连通) |
## 任务关联规范
创建任务时设置 `link_role` 并加阶段前缀:
| link_role | 阶段前缀 | 所属阶段 | 权重 |
|-----------|----------|----------|------|
| prd | 【评审】 | analysis | 10% |
| design | 【评审】 | design | 5% |
| implementation | 【开发】 | dev | 50% |
| code_review | 【代码评审】 | review | 5% |
| test | 【测试】 | testing | 15% |
| deploy | 【部署】 | staging/released | 5% |
| verification | 【验收】 | released | 5% |
| documentation | 【文档】 | any | 5% |
**进度计算**:按 link_role 权重统计已完成任务。
## 标准任务结构(阶段化)
```
需求 REQ-xxx
├── 📝 analysis 阶段
│ └── 【评审】PRD: {需求标题} (linkRole: prd)
├── 📐 design 阶段
│ └── 【评审】技术设计: {需求标题} (linkRole: design)
├── 💻 dev 阶段
│ ├── 【开发-后端】{描述} (linkRole: implementation)
│ └── 【开发-前端】{描述} (linkRole: implementation)
├── 🔍 review 阶段
│ └── 【代码评审】CR: {需求标题} (linkRole: code_review)
├── 🧪 testing 阶段
│ └── 【测试】集成测试: {需求标题} (linkRole: test)
├── 🚀 staging 阶段
│ └── 【部署】部署到 staging (singapore) (linkRole: deploy)
└── 🏁 released 阶段
├── 【部署】部署到 prod (tools_ai_proj) (linkRole: deploy)
└── 【验收】PDV: {需求标题} (linkRole: verification)
```
**命名规则**:所有任务标题必须以阶段前缀开头(如【评审】、【开发】、【部署】)。
## 环境配置
**双环境 MCP 配置**:区分开发测试和生产环境
```json
// ~/.claude/.mcp.json
{
"mcpServers": {
"ai-proj-dev": {
"type": "stdio",
"command": "node",
"args": ["/path/to/mcp-task-bridge/dist/index.js"],
"env": {
"TASK_API_BASE": "http://localhost:8080/api/v1",
"TASK_API_TOKEN": "aiproj_pk_xxx...",
"NODE_ENV": "development"
}
},
"ai-proj-prod": {
"type": "stdio",
"command": "node",
"args": ["/path/to/mcp-task-bridge/dist/index.js"],
"env": {
"TASK_API_BASE": "https://ai.pipexerp.com/api/v1",
"TASK_API_TOKEN": "aiproj_pk_xxx...",
"NODE_ENV": "production"
}
}
}
}
```
**环境使用指南**
| 环境 | 使用场景 | 工具前缀 |
|------|----------|----------|
| `ai-proj-dev` | 功能测试、流程验证、本地调试 | `mcp__ai-proj-dev__*` |
| `ai-proj-prod` | 正式需求管理、生产数据操作 | `mcp__ai-proj-prod__*` |
**跨机器支持**
- `ai-proj-dev` 支持 melbourne 和 adelaide 机器的本地环境(都是 localhost:8080
- 无论在哪台开发机器上,都使用 `ai-proj-dev` 连接本地 API
**项目配置**
```json
// .claude/settings.local.json
{
"env": {
"REQUIREMENT_PROJECT": "coolbuy-paas"
}
}
```
## 思源笔记集成
归档时自动同步 5 阶段文档到思源笔记:
- 路径:`需求管理/REQ-XXXX/`
- 文档01-PRD.md ~ 05-生命周期总结.md
手动同步:`/req sync-siyuan [REQ-ID]`
## 邮件通知
发送邮件:`/req notify [REQ-ID] --type <prd|dev|test|deploy|archive>`
默认收件人:项目邮件组(见项目配置)
---
## Memory 隔离规则(强制,源自 devflow-claude 借鉴)
**规则涉及生命周期文档产出PRD / 设计 / 测试报告 / 部署报告 / 生命周期总结)时,禁止受 auto-memory 影响产出物结构。**
### 禁止行为
1. 不得跳过或合并 5 阶段文档的任一阶段01-PRD ~ 05-生命周期总结)
2. 不得因 memory 里的历史项目跳过章节
3. 不得因 memory 中的"精简偏好"缩减文档结构
4. 不得读取 `~/.claude/projects/*/memory/` 生成这些文档的正文
### 允许行为
- memory 可影响**交互风格**(如提问详略)
- memory 可影响**通知习惯**(如默认 CC 某人)
- memory 可影响**触发时机**(如归档时是否自动同步思源)
### Why
需求生命周期文档对应审计和交付物。结构变化会破坏检索、对标、复盘。memory 应调节"怎么聊",不应调节"最终文档长什么样"。
**参考**devflow-claude `plugins/req/commands/_common.md` 同名规则,以及本项目 REQ-20260416-0017。