chore(marketplace): add publish-plugin, rewrite init.sh, cleanup obsolete plugins
- Add publish-plugin: marketplace publish + Feishu bot notification - Rewrite init.sh: SSE-first, fixed prod API, remove env selection - Update CLAUDE.md, README.md, claude-config.yaml - Update skills: req-plugin, req-prd-plugin, pull-request-plugin - Delete sync-skills.sh (obsolete) - Delete deprecated plugins: skills-ops/*, skills-projects/*, old skills-dev/req duplicates - Regenerate marketplace.json (27 plugins) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,9 +24,9 @@
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "agent-swarm-plugin",
|
||||
"source": "./skills-dev/agent-swarm-plugin",
|
||||
"description": "Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.",
|
||||
"name": "publish-plugin",
|
||||
"source": "./skills-core/publish-plugin",
|
||||
"description": "发布 ai-proj-helper 技能市场更新并通知飞书群。当用户提到发布、publish、更新技能市场时自动激活。",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
@@ -61,19 +61,6 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "dev-plugin",
|
||||
"source": "./skills-dev/dev-plugin",
|
||||
"description": "Plugin for dev",
|
||||
"version": "1.0.0",
|
||||
"category": "development",
|
||||
"keywords": [
|
||||
"development",
|
||||
"coding",
|
||||
"workflow"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "dev-test-plugin",
|
||||
"source": "./skills-dev/dev-test-plugin",
|
||||
@@ -87,43 +74,6 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "finishing-a-development-branch-plugin",
|
||||
"source": "./skills-dev/finishing-a-development-branch-plugin",
|
||||
"description": "Plugin for finishing-a-development-branch",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "frontend-design-plugin",
|
||||
"source": "./skills-dev/frontend-design-plugin",
|
||||
"description": "Plugin for frontend-design",
|
||||
"version": "1.0.0",
|
||||
"category": "development",
|
||||
"keywords": [
|
||||
"development",
|
||||
"coding",
|
||||
"workflow"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "gitea-plugin",
|
||||
"source": "./skills-dev/gitea-plugin",
|
||||
"description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "pull-request-plugin",
|
||||
"source": "./skills-dev/pull-request-plugin",
|
||||
@@ -137,44 +87,6 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "executing-plans-plugin",
|
||||
"source": "./skills-req/executing-plans-plugin",
|
||||
"description": "Plugin for executing-plans",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-commands-plugin",
|
||||
"source": "./skills-req/req-commands-plugin",
|
||||
"description": "需求命令详细参考。含撰写命令(new/draft/edit/check/split/history/compare)和流程命令(submit/review/phase/next/deploy/done)。",
|
||||
"version": "2.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-deploy-plugin",
|
||||
"source": "./skills-req/req-deploy-plugin",
|
||||
"description": "Plugin for req-deploy",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-dev-plugin",
|
||||
"source": "./skills-req/req-dev-plugin",
|
||||
@@ -214,19 +126,6 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-review-plugin",
|
||||
"source": "./skills-req/req-review-plugin",
|
||||
"description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-test-gate-plugin",
|
||||
"source": "./skills-req/req-test-gate-plugin",
|
||||
@@ -240,83 +139,6 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-workflow-plugin",
|
||||
"source": "./skills-req/req-workflow-plugin",
|
||||
"description": "需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。",
|
||||
"version": "1.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "requirement-plugin",
|
||||
"source": "./skills-req/requirement-plugin",
|
||||
"description": "[已废弃] 需求撰写功能已合并到 req-plugin。请使用 /req 命令。",
|
||||
"version": "2.0.0",
|
||||
"category": "productivity",
|
||||
"keywords": [
|
||||
"project-management",
|
||||
"tasks",
|
||||
"requirements"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "openclaw-ops-plugin",
|
||||
"source": "./skills-ops/openclaw-ops-plugin",
|
||||
"description": "Plugin for openclaw-ops",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "openclaw-plugin",
|
||||
"source": "./skills-ops/openclaw-plugin",
|
||||
"description": "OpenClaw (龙虾) - Remote AI compute orchestration system. Dispatches requirements to Claude Code instances on remote machines, monitors execution, and aggregates results.",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ops-servers-plugin",
|
||||
"source": "./skills-ops/ops-servers-plugin",
|
||||
"description": "Plugin for ops-servers",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "ops-tools-plugin",
|
||||
"source": "./skills-ops/ops-tools-plugin",
|
||||
"description": "Plugin for ops-tools",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "data-excel-plugin",
|
||||
"source": "./skills-integration/data-excel-plugin",
|
||||
@@ -471,9 +293,9 @@
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "coolbuy-legacy-plugin",
|
||||
"source": "./skills-projects/coolbuy-legacy-plugin",
|
||||
"description": "酷采2.0团购管理系统测试与维护。用于酷采2.0系统的功能测试、问题排查、需求验证和对比测试。",
|
||||
"name": "gitea-plugin",
|
||||
"source": "./skills-personal/gitea-plugin",
|
||||
"description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
@@ -483,10 +305,10 @@
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "coolbuy-paas-plugin",
|
||||
"source": "./skills-projects/coolbuy-paas-plugin",
|
||||
"description": "酷采3.0 SaaS 租户端开发与测试。用于商品管理、订单管理等业务模块开发,以及酷采2.0系统对比测试。",
|
||||
"version": "1.3.0",
|
||||
"name": "openclaw-plugin",
|
||||
"source": "./skills-personal/openclaw-plugin",
|
||||
"description": "OpenClaw (龙虾) 远程 AI 计算调度系统 - 概念设计与运维管理",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
@@ -495,21 +317,9 @@
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "coolbuy-platform-plugin",
|
||||
"source": "./skills-projects/coolbuy-platform-plugin",
|
||||
"description": "Coolbuy SaaS 平台管理端开发与部署。用于平台端前后端开发、租户管理、部署发布、翻译检查等任务。",
|
||||
"version": "1.0.9",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "enjoysa-deploy-plugin",
|
||||
"source": "./skills-projects/enjoysa-deploy-plugin",
|
||||
"description": "EnjoySA 项目部署到新加坡服务器",
|
||||
"name": "ops-tools-plugin",
|
||||
"source": "./skills-personal/ops-tools-plugin",
|
||||
"description": "Plugin for ops-tools",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
@@ -519,18 +329,6 @@
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "enjoysa-plugin",
|
||||
"source": "./skills-projects/enjoysa-plugin",
|
||||
"description": "Plugin for enjoysa",
|
||||
"version": "1.0.0",
|
||||
"category": "utility",
|
||||
"keywords": [
|
||||
"utility",
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "qiudl-personal-plugin",
|
||||
"source": "./skills-personal/qiudl-personal-plugin",
|
||||
@@ -542,6 +340,19 @@
|
||||
"tools"
|
||||
],
|
||||
"strict": false
|
||||
},
|
||||
{
|
||||
"name": "req-deploy-plugin",
|
||||
"source": "./skills-personal/req-deploy-plugin",
|
||||
"description": "Plugin for req-deploy",
|
||||
"version": "1.0.0",
|
||||
"category": "devops",
|
||||
"keywords": [
|
||||
"devops",
|
||||
"deployment",
|
||||
"operations"
|
||||
],
|
||||
"strict": false
|
||||
}
|
||||
]
|
||||
}
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,6 +11,9 @@ skills-personal/
|
||||
# MCP generated config
|
||||
.mcp.json
|
||||
|
||||
# MCP bridge (cloned by init.sh for stdio mode)
|
||||
mcp-task-bridge/
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
23
CLAUDE.md
23
CLAUDE.md
@@ -8,27 +8,24 @@ Claude Code 技能市场 + MCP 配置管理工具。
|
||||
./init.sh
|
||||
```
|
||||
|
||||
交互式配置 MCP 连接和生成 marketplace.json。支持命令行参数:
|
||||
交互式配置 MCP 连接(默认 SSE 模式)。支持命令行参数:
|
||||
|
||||
```bash
|
||||
./init.sh --mode stdio --env prod --token YOUR_TOKEN
|
||||
./init.sh --mode sse --token aiproj_pk_xxx
|
||||
```
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
ai-proj-helper/
|
||||
├── skills-dev/ # 开发 (9): dev, dev-arch, dev-coding, dev-test, frontend-design, agent-swarm, pull-request, finishing-a-development-branch, gitea
|
||||
├── skills-req/ # 需求 (10): req, req-commands, req-dev, req-prd, req-review, req-test-gate, req-workflow, req-deploy, requirement, executing-plans
|
||||
├── skills-ops/ # 运维 (4): ops-tools, ops-servers, openclaw, openclaw-ops
|
||||
├── skills-core/ # 基础设施 (1): ai-proj
|
||||
├── skills-dev/ # 开发 (4): dev-arch, dev-coding, dev-test, pull-request
|
||||
├── skills-req/ # 需求 (4): req, req-prd, req-dev, req-test-gate
|
||||
├── skills-integration/ # 集成 (8): feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel, doubao-voice
|
||||
├── skills-biz/ # 商务 (4): biz-contract, biz-ops, biz-plan, finance
|
||||
├── skills-workflow/ # 工作流 (7): ai-proj, save-session, reload-session, read-session, search-sessions, session, skill-manager
|
||||
├── skills-projects/ # 项目 (5): coolbuy-legacy, coolbuy-paas, coolbuy-platform, enjoysa, enjoysa-deploy
|
||||
├── skills-personal/ # 个人(.gitignore 排除)
|
||||
├── claude-config.yaml # 技能启用/禁用 + MCP 配置
|
||||
├── init.sh # MCP + marketplace 初始化
|
||||
├── sync-skills.sh # 从 ~/.claude/skills/ 同步技能
|
||||
├── init.sh # MCP 初始化
|
||||
└── generate-marketplace.py
|
||||
```
|
||||
|
||||
@@ -50,14 +47,6 @@ skills:
|
||||
|
||||
重新运行 `./init.sh` 或 `python3 generate-marketplace.py`。
|
||||
|
||||
## MCP 环境
|
||||
|
||||
| 环境 | API 地址 |
|
||||
|------|----------|
|
||||
| dev | http://localhost:8080/api/v1 |
|
||||
| staging | https://ai-staging.pipexerp.com/api/v1 |
|
||||
| prod | https://ai.pipexerp.com/api/v1 |
|
||||
|
||||
## 技能目录说明
|
||||
|
||||
- `skills-personal/` 不被 Git 跟踪,用于存放个人配置和工具
|
||||
|
||||
56
README.md
56
README.md
@@ -11,7 +11,7 @@ Claude Code 技能市场 + MCP 配置管理工具。整合通用技能、项目
|
||||
git clone https://gitea.pipexerp.com/pipexerp/ai-proj-helper.git
|
||||
cd ai-proj-helper
|
||||
|
||||
# 2. 运行初始化(交互式配置 MCP + 生成 marketplace)
|
||||
# 2. 运行初始化(交互式配置 MCP 连接)
|
||||
./init.sh
|
||||
|
||||
# 3. 添加技能市场
|
||||
@@ -21,7 +21,7 @@ cd ai-proj-helper
|
||||
也可以使用命令行参数跳过交互:
|
||||
|
||||
```bash
|
||||
./init.sh --mode stdio --env prod --token YOUR_TOKEN
|
||||
./init.sh --mode sse --token aiproj_pk_xxx
|
||||
```
|
||||
|
||||
## 目录结构
|
||||
@@ -30,32 +30,29 @@ cd ai-proj-helper
|
||||
ai-proj-helper/
|
||||
├── .claude-plugin/marketplace.json # 自动生成
|
||||
├── claude-config.yaml # 技能启用/禁用 + MCP 配置
|
||||
├── init.sh # MCP + marketplace 初始化
|
||||
├── sync-skills.sh # 同步本地技能
|
||||
├── init.sh # MCP 初始化
|
||||
├── generate-marketplace.py # marketplace 生成器
|
||||
├── skills-dev/ # 开发 (9)
|
||||
├── skills-req/ # 需求管理 (10)
|
||||
├── skills-ops/ # 运维 (4)
|
||||
├── skills-core/ # 基础设施 (1)
|
||||
├── skills-dev/ # 开发 (4)
|
||||
├── skills-req/ # 需求管理 (4)
|
||||
├── skills-integration/ # 第三方集成 (8)
|
||||
├── skills-biz/ # 商务 (4)
|
||||
├── skills-workflow/ # 工作流 (7)
|
||||
├── skills-projects/ # 项目特定 (5)
|
||||
└── skills-personal/ # 个人(.gitignore 排除)
|
||||
```
|
||||
|
||||
## 可用技能 (49)
|
||||
## 可用技能 (26)
|
||||
|
||||
### skills-dev/ — 开发 (9)
|
||||
### skills-core/ — 基础设施 (1)
|
||||
|
||||
dev, dev-arch, dev-coding, dev-test, frontend-design, agent-swarm, pull-request, finishing-a-development-branch, gitea
|
||||
ai-proj
|
||||
|
||||
### skills-req/ — 需求管理 (10)
|
||||
### skills-dev/ — 开发 (4)
|
||||
|
||||
req, req-commands, req-dev, req-prd, req-review, req-test-gate, req-workflow, req-deploy, requirement, executing-plans
|
||||
dev-arch, dev-coding, dev-test, pull-request
|
||||
|
||||
### skills-ops/ — 运维 (4)
|
||||
### skills-req/ — 需求管理 (4)
|
||||
|
||||
ops-tools, ops-servers, openclaw, openclaw-ops
|
||||
req, req-prd, req-dev, req-test-gate
|
||||
|
||||
### skills-integration/ — 第三方集成 (8)
|
||||
|
||||
@@ -65,13 +62,9 @@ feishu, feishu-bitable, feishu-docx, wecom, siyuan, siyuan-to-feishu, data-excel
|
||||
|
||||
biz-contract, biz-ops, biz-plan, finance
|
||||
|
||||
### skills-workflow/ — 工作流 (7)
|
||||
### skills-personal/ — 个人 (5)
|
||||
|
||||
ai-proj, save-session, reload-session, read-session, search-sessions, session, skill-manager
|
||||
|
||||
### skills-projects/ — 项目特定 (5)
|
||||
|
||||
coolbuy-legacy, coolbuy-paas, coolbuy-platform, enjoysa, enjoysa-deploy
|
||||
gitea, openclaw, ops-tools, qiudl-personal, req-deploy
|
||||
|
||||
## 配置管理
|
||||
|
||||
@@ -81,8 +74,7 @@ coolbuy-legacy, coolbuy-paas, coolbuy-platform, enjoysa, enjoysa-deploy
|
||||
version: "1.0"
|
||||
|
||||
mcp:
|
||||
mode: stdio # stdio | sse
|
||||
env: prod # dev | staging | prod
|
||||
mode: sse # sse | stdio
|
||||
|
||||
skills:
|
||||
disabled: [] # 禁用的技能列表
|
||||
@@ -93,22 +85,6 @@ skills:
|
||||
|
||||
编辑 `claude-config.yaml` 添加要禁用的技能名称,然后重新运行 `./init.sh` 或 `python3 generate-marketplace.py`。
|
||||
|
||||
## 同步本地技能
|
||||
|
||||
将 `~/.claude/skills/` 中的技能同步到仓库:
|
||||
|
||||
```bash
|
||||
./sync-skills.sh
|
||||
```
|
||||
|
||||
## MCP 环境
|
||||
|
||||
| 环境 | API 地址 | 用途 |
|
||||
|------|----------|------|
|
||||
| dev | http://localhost:8080 | 本地开发 |
|
||||
| staging | https://ai-staging.pipexerp.com | 测试环境 |
|
||||
| prod | https://ai.pipexerp.com | 生产环境 |
|
||||
|
||||
## 作者
|
||||
|
||||
**Donglin Lai (qiudl)** - qiudl@zhiyuncai.com
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
version: "1.0"
|
||||
|
||||
mcp:
|
||||
mode: stdio # stdio | sse
|
||||
env: prod # dev | staging | prod
|
||||
mode: sse # sse | stdio
|
||||
# Token 不存储在此文件,由 init.sh 引导配置
|
||||
|
||||
skills:
|
||||
|
||||
@@ -19,11 +19,8 @@ SKILL_DIRS = [
|
||||
("core", "skills-core"),
|
||||
("dev", "skills-dev"),
|
||||
("req", "skills-req"),
|
||||
("ops", "skills-ops"),
|
||||
("integration", "skills-integration"),
|
||||
("biz", "skills-biz"),
|
||||
("workflow", "skills-workflow"),
|
||||
("projects", "skills-projects"),
|
||||
("personal", "skills-personal"),
|
||||
]
|
||||
|
||||
|
||||
121
init.sh
121
init.sh
@@ -1,32 +1,31 @@
|
||||
#!/bin/bash
|
||||
# ai-proj-helper 初始化脚本
|
||||
# 配置 MCP 服务器 + 生成 marketplace.json
|
||||
# ai-proj-helper MCP 初始化脚本
|
||||
# 为用户配置 ai-proj MCP 连接
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
MCP_CONFIG="$HOME/.claude/.mcp.json"
|
||||
MCP_BRIDGE_DIR="$HOME/coding/qiudl/new-ai-proj/mcp-task-bridge"
|
||||
MCP_BRIDGE_DIR="$SCRIPT_DIR/mcp-task-bridge"
|
||||
CONFIG_FILE="$SCRIPT_DIR/claude-config.yaml"
|
||||
API_BASE="https://ai.pipexerp.com/api/v1"
|
||||
SSE_URL="${API_BASE}/mcp/sse"
|
||||
|
||||
# Default values
|
||||
MODE=""
|
||||
ENV=""
|
||||
TOKEN=""
|
||||
|
||||
# ── Parse command line arguments ──────────────────────────────────────
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--mode) MODE="$2"; shift 2 ;;
|
||||
--env) ENV="$2"; shift 2 ;;
|
||||
--token) TOKEN="$2"; shift 2 ;;
|
||||
-h|--help)
|
||||
echo "Usage: ./init.sh [--mode stdio|sse] [--env dev|staging|prod] [--token PAT_TOKEN]"
|
||||
echo "Usage: ./init.sh [--mode sse|stdio] [--token MCP_API_KEY]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --mode MCP connection mode: stdio (local) or sse (remote)"
|
||||
echo " --env Environment: dev, staging, or prod"
|
||||
echo " --token Personal Access Token for ai-proj API"
|
||||
echo " --mode MCP connection mode: sse (remote, recommended) or stdio (local)"
|
||||
echo " --token MCP API Key (aiproj_pk_xxx)"
|
||||
echo ""
|
||||
echo "Without arguments, runs in interactive mode."
|
||||
exit 0
|
||||
@@ -50,75 +49,71 @@ read_config_value() {
|
||||
echo "$default"
|
||||
}
|
||||
|
||||
CONFIG_MODE=$(read_config_value "mode" "stdio")
|
||||
CONFIG_ENV=$(read_config_value "env" "prod")
|
||||
CONFIG_MODE=$(read_config_value "mode" "sse")
|
||||
|
||||
# ── Interactive mode selection ────────────────────────────────────────
|
||||
if [ -z "$MODE" ]; then
|
||||
echo "┌─────────────────────────────────────┐"
|
||||
echo "│ ai-proj-helper 初始化 │"
|
||||
echo "│ ai-proj MCP 初始化 │"
|
||||
echo "└─────────────────────────────────────┘"
|
||||
echo ""
|
||||
echo "MCP 连接模式:"
|
||||
echo " 1) stdio - 本地进程 (需要 mcp-task-bridge)"
|
||||
echo " 2) sse - 远程 SSE 连接"
|
||||
echo " 1) sse - 远程 SSE 连接 (推荐,零依赖)"
|
||||
echo " 2) stdio - 本地进程 (需要 Node.js + mcp-task-bridge)"
|
||||
echo ""
|
||||
read -p "选择模式 [1/2] (default: $([ "$CONFIG_MODE" = "sse" ] && echo "2" || echo "1")): " mode_choice
|
||||
read -p "选择模式 [1/2] (default: $([ "$CONFIG_MODE" = "stdio" ] && echo "2" || echo "1")): " mode_choice
|
||||
case "$mode_choice" in
|
||||
2|sse) MODE="sse" ;;
|
||||
*) MODE="stdio" ;;
|
||||
2|stdio) MODE="stdio" ;;
|
||||
*) MODE="sse" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# ── Interactive environment selection ─────────────────────────────────
|
||||
if [ -z "$ENV" ]; then
|
||||
echo ""
|
||||
echo "环境:"
|
||||
echo " 1) dev - http://localhost:8080"
|
||||
echo " 2) staging - https://ai-staging.pipexerp.com"
|
||||
echo " 3) prod - https://ai.pipexerp.com"
|
||||
echo ""
|
||||
default_num=3
|
||||
[ "$CONFIG_ENV" = "dev" ] && default_num=1
|
||||
[ "$CONFIG_ENV" = "staging" ] && default_num=2
|
||||
read -p "选择环境 [1/2/3] (default: $default_num): " env_choice
|
||||
case "$env_choice" in
|
||||
1|dev) ENV="dev" ;;
|
||||
2|staging) ENV="staging" ;;
|
||||
*) ENV="prod" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# ── Resolve API base URL ─────────────────────────────────────────────
|
||||
case "$ENV" in
|
||||
dev) API_BASE="http://localhost:8080/api/v1" ;;
|
||||
staging) API_BASE="https://ai-staging.pipexerp.com/api/v1" ;;
|
||||
prod) API_BASE="https://ai.pipexerp.com/api/v1" ;;
|
||||
esac
|
||||
|
||||
# ── Token input ───────────────────────────────────────────────────────
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo ""
|
||||
echo "请输入 AI-Proj Personal Access Token (PAT):"
|
||||
echo " 获取方式: 登录 AI-Proj → 设置 → API Tokens → 创建"
|
||||
echo "请输入 MCP API Key:"
|
||||
echo " 格式: aiproj_pk_xxxxxxxx"
|
||||
echo " 获取: 登录 AI-Proj → 设置 → MCP API Keys → 创建"
|
||||
echo ""
|
||||
read -sp "Token: " TOKEN
|
||||
read -sp "API Key: " TOKEN
|
||||
echo ""
|
||||
fi
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo "❌ Token 不能为空"
|
||||
echo "❌ API Key 不能为空"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "配置信息:"
|
||||
echo " 模式: $MODE"
|
||||
echo " 环境: $ENV ($API_BASE)"
|
||||
if [ "$MODE" = "sse" ]; then
|
||||
echo " SSE: $SSE_URL"
|
||||
else
|
||||
echo " API: $API_BASE"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# ── SSE mode ─────────────────────────────────────────────────────────
|
||||
if [ "$MODE" = "sse" ]; then
|
||||
mkdir -p "$(dirname "$MCP_CONFIG")"
|
||||
cat > "$MCP_CONFIG" << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"ai-proj": {
|
||||
"type": "sse",
|
||||
"url": "$SSE_URL",
|
||||
"headers": {
|
||||
"X-API-Key": "$TOKEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
echo "✅ 已生成 $MCP_CONFIG (SSE 模式)"
|
||||
|
||||
# ── stdio mode: ensure mcp-task-bridge ────────────────────────────────
|
||||
if [ "$MODE" = "stdio" ]; then
|
||||
elif [ "$MODE" = "stdio" ]; then
|
||||
if [ ! -d "$MCP_BRIDGE_DIR" ]; then
|
||||
echo "📦 mcp-task-bridge 未找到,正在克隆..."
|
||||
git clone https://gitea.pipexerp.com/pipexerp/mcp-task-bridge.git "$MCP_BRIDGE_DIR"
|
||||
@@ -134,7 +129,6 @@ if [ "$MODE" = "stdio" ]; then
|
||||
|
||||
BRIDGE_ENTRY="$MCP_BRIDGE_DIR/dist/index.js"
|
||||
|
||||
# Generate .mcp.json for stdio mode
|
||||
mkdir -p "$(dirname "$MCP_CONFIG")"
|
||||
cat > "$MCP_CONFIG" << EOF
|
||||
{
|
||||
@@ -153,37 +147,12 @@ if [ "$MODE" = "stdio" ]; then
|
||||
}
|
||||
EOF
|
||||
echo "✅ 已生成 $MCP_CONFIG (stdio 模式)"
|
||||
|
||||
elif [ "$MODE" = "sse" ]; then
|
||||
# Generate .mcp.json for SSE mode
|
||||
SSE_URL="${API_BASE%/api/v1}/mcp/sse"
|
||||
mkdir -p "$(dirname "$MCP_CONFIG")"
|
||||
cat > "$MCP_CONFIG" << EOF
|
||||
{
|
||||
"mcpServers": {
|
||||
"ai-proj": {
|
||||
"type": "sse",
|
||||
"url": "$SSE_URL",
|
||||
"headers": {
|
||||
"Authorization": "Bearer $TOKEN"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
echo "✅ 已生成 $MCP_CONFIG (SSE 模式)"
|
||||
fi
|
||||
|
||||
# ── Generate marketplace.json ─────────────────────────────────────────
|
||||
echo ""
|
||||
echo "🔄 生成 marketplace.json..."
|
||||
cd "$SCRIPT_DIR"
|
||||
python3 generate-marketplace.py
|
||||
|
||||
echo ""
|
||||
echo "┌─────────────────────────────────────┐"
|
||||
echo "│ ✅ 初始化完成! │"
|
||||
echo "└─────────────────────────────────────┘"
|
||||
echo ""
|
||||
echo "下次启动 Claude Code 即可使用 MCP 工具。"
|
||||
echo "如需更新技能配置,编辑 claude-config.yaml 后重新运行 ./init.sh"
|
||||
echo "如需更改模式,编辑 claude-config.yaml 后重新运行 ./init.sh"
|
||||
|
||||
8
skills-core/publish-plugin/.claude-plugin/plugin.json
Normal file
8
skills-core/publish-plugin/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "publish-plugin",
|
||||
"description": "发布 ai-proj-helper 技能市场更新并通知飞书群。当用户提到发布、publish、更新技能市场时自动激活。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
169
skills-core/publish-plugin/skills/SKILL.md
Normal file
169
skills-core/publish-plugin/skills/SKILL.md
Normal file
@@ -0,0 +1,169 @@
|
||||
---
|
||||
name: publish
|
||||
description: 发布 ai-proj-helper 技能市场更新并通知飞书群。用户说 /publish 时激活。
|
||||
user_invocable: true
|
||||
---
|
||||
|
||||
# publish - 技能市场发布与通知
|
||||
|
||||
发布 ai-proj-helper 的技能变更,重新生成 marketplace.json,提交推送到 Gitea,并通过飞书 Webhook 通知团队。
|
||||
|
||||
## 命令
|
||||
|
||||
**`/publish [消息]`** — 发布当前变更并通知飞书
|
||||
|
||||
## 流程
|
||||
|
||||
```
|
||||
1. 检查工作目录状态 (git status)
|
||||
2. 运行 generate-marketplace.py 重新生成 marketplace.json
|
||||
3. 生成变更摘要(新增/更新/删除了哪些技能)
|
||||
4. git add + commit + push
|
||||
5. 发送飞书卡片通知
|
||||
```
|
||||
|
||||
## 详细步骤
|
||||
|
||||
### Step 1: 检查工作目录
|
||||
|
||||
```bash
|
||||
cd <ai-proj-helper-root>
|
||||
git status
|
||||
```
|
||||
|
||||
确认当前在正确的仓库中。如果没有任何变更(包括 marketplace.json),提示用户无需发布。
|
||||
|
||||
### Step 2: 重新生成 marketplace.json
|
||||
|
||||
```bash
|
||||
cd <ai-proj-helper-root>
|
||||
python3 generate-marketplace.py
|
||||
```
|
||||
|
||||
输出会显示扫描到的各分类技能数量。
|
||||
|
||||
### Step 3: 生成变更摘要
|
||||
|
||||
对比 `git diff` 结果,提取变更内容:
|
||||
|
||||
- **新增技能**:新出现的 `*-plugin/` 目录
|
||||
- **更新技能**:已有技能的 SKILL.md 或 plugin.json 变更
|
||||
- **删除技能**:被移除的 `*-plugin/` 目录
|
||||
- **配置变更**:claude-config.yaml、init.sh 等基础文件变更
|
||||
|
||||
摘要格式:
|
||||
```
|
||||
新增: feishu-bitable-plugin, doubao-voice-plugin
|
||||
更新: req-plugin (SKILL.md)
|
||||
删除: old-plugin
|
||||
配置: init.sh 默认改为 SSE 模式
|
||||
```
|
||||
|
||||
### Step 4: Git 提交并推送
|
||||
|
||||
```bash
|
||||
cd <ai-proj-helper-root>
|
||||
git add -A
|
||||
git commit -m "chore(marketplace): <变更摘要>"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
Commit message 示例:
|
||||
- `chore(marketplace): add feishu-bitable-plugin, update req-plugin`
|
||||
- `chore(marketplace): update init.sh to SSE default`
|
||||
|
||||
### Step 5: 飞书通知
|
||||
|
||||
**Webhook 地址**:从环境变量 `FEISHU_DEPLOY_WEBHOOK` 读取,配置在 `~/.config/devops/credentials.env`。
|
||||
|
||||
如果环境变量未设置,AskUserQuestion 询问用户提供 webhook URL,并建议添加到 credentials.env。
|
||||
|
||||
**卡片格式**(必须用 legacy format,不用 schema 2.0):
|
||||
|
||||
```bash
|
||||
# 先 source 凭据
|
||||
source ~/.config/devops/credentials.env
|
||||
|
||||
# 构建卡片 JSON(必须写文件,不能直接传中文 JSON)
|
||||
cat > /tmp/publish_notify.json << 'CARD_EOF'
|
||||
{
|
||||
"msg_type": "interactive",
|
||||
"card": {
|
||||
"header": {
|
||||
"title": {"tag": "plain_text", "content": "AI 技能市场更新"},
|
||||
"template": "green"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"tag": "div",
|
||||
"text": {"tag": "lark_md", "content": "CHANGE_SUMMARY_HERE"}
|
||||
},
|
||||
{
|
||||
"tag": "div",
|
||||
"text": {"tag": "lark_md", "content": "**提交**: COMMIT_HASH_HERE"}
|
||||
},
|
||||
{
|
||||
"tag": "action",
|
||||
"actions": [{
|
||||
"tag": "button",
|
||||
"text": {"tag": "plain_text", "content": "查看仓库"},
|
||||
"type": "primary",
|
||||
"url": "https://gitea.pipexerp.com/pipexerp/ai-proj-helper"
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
CARD_EOF
|
||||
|
||||
# 替换占位符后发送
|
||||
curl -s -X POST "$FEISHU_DEPLOY_WEBHOOK" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @/tmp/publish_notify.json
|
||||
```
|
||||
|
||||
**重要**:
|
||||
- 必须用 legacy card format(无 schema 字段),否则返回 ErrCode 11246
|
||||
- 中文内容必须先写文件再 `curl -d @file`,直接传会出现 "blank argument" 错误
|
||||
- `template` 颜色:`green`=成功,`red`=失败,`blue`=信息
|
||||
|
||||
### 自定义消息
|
||||
|
||||
用户可以在 `/publish` 后附加自定义消息,会追加到卡片内容中:
|
||||
|
||||
```
|
||||
/publish 新增飞书多维表格技能,支持批量数据导入
|
||||
```
|
||||
|
||||
卡片内容将包含:
|
||||
```
|
||||
**更新说明**: 新增飞书多维表格技能,支持批量数据导入
|
||||
|
||||
**变更**: 新增 feishu-bitable-plugin
|
||||
**提交**: abc1234
|
||||
```
|
||||
|
||||
## 环境配置
|
||||
|
||||
在 `~/.config/devops/credentials.env` 中添加:
|
||||
|
||||
```bash
|
||||
# 飞书部署通知 Webhook
|
||||
FEISHU_DEPLOY_WEBHOOK="https://open.feishu.cn/open-apis/bot/v2/hook/YOUR_WEBHOOK_KEY"
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
| 场景 | 处理 |
|
||||
|------|------|
|
||||
| 无变更可提交 | 提示用户,跳过后续步骤 |
|
||||
| generate-marketplace.py 失败 | 显示错误,中止发布 |
|
||||
| git push 失败 | 显示错误,建议手动解决冲突 |
|
||||
| FEISHU_DEPLOY_WEBHOOK 未配置 | AskUserQuestion 询问 webhook URL |
|
||||
| 飞书通知发送失败 | 显示 curl 返回值,提示但不阻断(代码已推送成功) |
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 此技能操作的仓库路径由 marketplace 插件根目录决定
|
||||
- 发布前确认 `generate-marketplace.py` 输出无异常
|
||||
- 飞书通知是 best-effort,失败不影响代码发布
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "agent-swarm-plugin",
|
||||
"description": "Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,406 +0,0 @@
|
||||
---
|
||||
name: agent-swarm
|
||||
description: Multi-agent orchestration using OpenAI Swarm patterns. Coordinate specialized agents for complex development workflows with handoffs and context sharing.
|
||||
---
|
||||
|
||||
# Agent Swarm - Multi-Agent Orchestration
|
||||
|
||||
基于 OpenAI Swarm 设计模式的多智能体协作系统,用于复杂开发任务的智能分解与协调。
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 1. Agent(智能体)
|
||||
每个 Agent 是具有特定职责的专家:
|
||||
- **Instructions**: Agent 的角色定义和行为准则
|
||||
- **Functions**: Agent 可以调用的工具函数
|
||||
- **Handoffs**: 何时移交给其他 Agent
|
||||
|
||||
### 2. Handoff(任务移交)
|
||||
Agent 之间的控制权转移机制:
|
||||
- 当前 Agent 完成自己的职责
|
||||
- 识别需要其他专长
|
||||
- 移交给最合适的 Agent
|
||||
|
||||
### 3. Context Variables(上下文变量)
|
||||
跨 Agent 共享的状态:
|
||||
- 项目目录
|
||||
- 技术栈信息
|
||||
- 当前进度
|
||||
- 发现的问题
|
||||
|
||||
---
|
||||
|
||||
## 预定义 Agent
|
||||
|
||||
### 1. Architect Agent(架构师)
|
||||
**职责**: 理解需求、技术选型、设计系统架构
|
||||
|
||||
**何时使用**:
|
||||
- 用户描述新功能或系统
|
||||
- 需要技术方案设计
|
||||
- 需要架构评审
|
||||
|
||||
**工具**:
|
||||
- Read codebase
|
||||
- Grep patterns
|
||||
- 设计文档生成
|
||||
|
||||
**Handoff to**:
|
||||
- Coder Agent(开始编码)
|
||||
- Reviewer Agent(评审设计)
|
||||
|
||||
---
|
||||
|
||||
### 2. Coder Agent(编码者)
|
||||
**职责**: 实现功能、编写代码、修复 bug
|
||||
|
||||
**何时使用**:
|
||||
- 架构师完成设计
|
||||
- 用户提出 bug 修复
|
||||
- 需要代码重构
|
||||
|
||||
**工具**:
|
||||
- Edit files
|
||||
- Write files
|
||||
- Git operations
|
||||
|
||||
**Handoff to**:
|
||||
- Tester Agent(代码完成后)
|
||||
- Architect Agent(遇到设计问题)
|
||||
|
||||
---
|
||||
|
||||
### 3. Tester Agent(测试员)
|
||||
**职责**: 编写测试、运行测试、验证功能
|
||||
|
||||
**何时使用**:
|
||||
- 代码编写完成
|
||||
- 需要测试覆盖
|
||||
- 验证 bug 修复
|
||||
|
||||
**工具**:
|
||||
- Run tests
|
||||
- Write test cases
|
||||
- Coverage reports
|
||||
|
||||
**Handoff to**:
|
||||
- Deployer Agent(测试通过)
|
||||
- Coder Agent(发现问题)
|
||||
|
||||
---
|
||||
|
||||
### 4. Deployer Agent(部署员)
|
||||
**职责**: 构建镜像、部署服务、监控上线
|
||||
|
||||
**何时使用**:
|
||||
- 测试全部通过
|
||||
- 需要发布到环境
|
||||
- 需要回滚版本
|
||||
|
||||
**工具**:
|
||||
- Docker build
|
||||
- SSH deployment
|
||||
- Health checks
|
||||
|
||||
**Handoff to**:
|
||||
- Monitor Agent(部署完成)
|
||||
- Coder Agent(部署失败)
|
||||
|
||||
---
|
||||
|
||||
### 5. Reviewer Agent(评审员)
|
||||
**职责**: 代码审查、文档审查、安全检查
|
||||
|
||||
**何时使用**:
|
||||
- PR 创建后
|
||||
- 重要功能完成
|
||||
- 需要质量把关
|
||||
|
||||
**工具**:
|
||||
- Diff analysis
|
||||
- Security scan
|
||||
- Best practices check
|
||||
|
||||
**Handoff to**:
|
||||
- Coder Agent(需要修改)
|
||||
- Deployer Agent(审查通过)
|
||||
|
||||
---
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基本调用
|
||||
|
||||
```bash
|
||||
/swarm start "在 new-ai-proj 中实现任务批量删除功能"
|
||||
```
|
||||
|
||||
**执行流程**:
|
||||
1. **Architect** 分析需求 → 设计 API 和前端交互
|
||||
2. **Coder** 实现后端 API → 实现前端 UI
|
||||
3. **Tester** 编写单元测试 → 运行测试
|
||||
4. **Reviewer** 代码审查 → 安全检查
|
||||
5. **Deployer** 部署到 staging → 验证功能
|
||||
|
||||
---
|
||||
|
||||
### 指定起始 Agent
|
||||
|
||||
```bash
|
||||
/swarm coder "修复 backend/handlers/task_handler.go 的空指针 bug"
|
||||
```
|
||||
|
||||
直接从 Coder Agent 开始,跳过架构设计阶段。
|
||||
|
||||
---
|
||||
|
||||
### 传递上下文
|
||||
|
||||
```bash
|
||||
/swarm start "优化数据库查询性能" \
|
||||
--context project=/Users/coolbuy-dev/coding/new-ai-proj \
|
||||
--context stack=Go,PostgreSQL,Redis \
|
||||
--context module=backend/services
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 查看执行轨迹
|
||||
|
||||
```bash
|
||||
/swarm trace
|
||||
```
|
||||
|
||||
显示 Agent 调用链:
|
||||
```
|
||||
Architect → analyzed requirements (3 min)
|
||||
↓ handoff: "Design complete, ready for implementation"
|
||||
Coder → implemented 5 files (12 min)
|
||||
↓ handoff: "Code complete, needs testing"
|
||||
Tester → wrote 8 test cases, all passed (5 min)
|
||||
↓ handoff: "Tests passed, ready for review"
|
||||
Reviewer → approved with 2 suggestions (2 min)
|
||||
↓ handoff: "Approved, ready for deployment"
|
||||
Deployer → deployed to staging, health check OK (3 min)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 配置文件
|
||||
|
||||
### swarm.yaml
|
||||
|
||||
在项目根目录创建 `swarm.yaml` 自定义 Agent 行为:
|
||||
|
||||
```yaml
|
||||
agents:
|
||||
architect:
|
||||
instructions: |
|
||||
你是系统架构师,专注于 Go + Vue.js 技术栈。
|
||||
遵循 RESTful API 设计原则。
|
||||
考虑性能、安全性、可维护性。
|
||||
max_turns: 5
|
||||
|
||||
coder:
|
||||
instructions: |
|
||||
你是 Go 后端工程师和 Vue.js 前端工程师。
|
||||
编写清晰、简洁、高性能的代码。
|
||||
遵循项目现有代码风格。
|
||||
tools:
|
||||
- Edit
|
||||
- Write
|
||||
- Bash
|
||||
max_turns: 10
|
||||
|
||||
tester:
|
||||
instructions: |
|
||||
你是测试工程师,编写全面的测试用例。
|
||||
确保边界条件、错误处理、并发安全。
|
||||
tools:
|
||||
- Bash
|
||||
- Write
|
||||
test_command: "go test ./... -v"
|
||||
max_turns: 5
|
||||
|
||||
context_variables:
|
||||
project_root: /Users/coolbuy-dev/coding/new-ai-proj
|
||||
backend_lang: Go 1.21
|
||||
frontend_framework: Vue 3
|
||||
database: PostgreSQL 15
|
||||
deployment_target: staging.ai.pipexerp.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 高级功能
|
||||
|
||||
### 1. 自定义 Agent
|
||||
|
||||
```yaml
|
||||
agents:
|
||||
database-optimizer:
|
||||
instructions: |
|
||||
你是数据库性能优化专家。
|
||||
分析慢查询、优化索引、设计缓存策略。
|
||||
functions:
|
||||
- explain_analyze
|
||||
- create_index
|
||||
- cache_design
|
||||
handoff_to:
|
||||
- coder # 实现优化方案
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 条件 Handoff
|
||||
|
||||
```yaml
|
||||
handoff_rules:
|
||||
- from: tester
|
||||
to: coder
|
||||
condition: "test_pass_rate < 90%"
|
||||
message: "测试失败率超过 10%,需要修复"
|
||||
|
||||
- from: tester
|
||||
to: deployer
|
||||
condition: "test_pass_rate == 100%"
|
||||
message: "所有测试通过,可以部署"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 并行 Agent
|
||||
|
||||
对于独立任务,多个 Agent 可以并行工作:
|
||||
|
||||
```bash
|
||||
/swarm parallel \
|
||||
"coder: 实现后端 API" \
|
||||
"coder: 实现前端 UI" \
|
||||
"tester: 编写 API 测试"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 与 Remote Coding 集成
|
||||
|
||||
在 OpenClaw 中调用本地 Claude Code 执行 Swarm 工作流:
|
||||
|
||||
```bash
|
||||
# OpenClaw 调用 Melbourne Claude Code
|
||||
ssh melbourne "cd /Users/coolbuy-dev/coding/new-ai-proj && \
|
||||
/opt/homebrew/bin/claude --dangerously-skip-permissions \
|
||||
-p '/swarm start 实现任务批量删除功能'"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实际案例
|
||||
|
||||
### 案例 1: 新功能开发
|
||||
|
||||
**任务**: "为 AI-Proj 实现需求批量导出功能"
|
||||
|
||||
**执行过程**:
|
||||
1. **Architect**:
|
||||
- 分析需求:导出格式(Excel/PDF)、筛选条件、数据脱敏
|
||||
- 设计 API: `POST /api/v1/requirements/export`
|
||||
- 设计前端:导出按钮、进度条、下载链接
|
||||
|
||||
2. **Coder**:
|
||||
- 后端实现 export service
|
||||
- 前端实现导出 UI 组件
|
||||
- 集成 file download 功能
|
||||
|
||||
3. **Tester**:
|
||||
- 测试大量数据导出(1000+ 需求)
|
||||
- 测试并发导出
|
||||
- 测试下载失败重试
|
||||
|
||||
4. **Reviewer**:
|
||||
- 检查文件大小限制
|
||||
- 检查内存泄漏风险
|
||||
- 检查数据权限控制
|
||||
|
||||
5. **Deployer**:
|
||||
- 部署到 staging
|
||||
- 验证导出功能
|
||||
- 监控资源使用
|
||||
|
||||
---
|
||||
|
||||
### 案例 2: Bug 修复
|
||||
|
||||
**任务**: "修复任务详情页加载缓慢问题"
|
||||
|
||||
**执行过程**:
|
||||
1. **Architect**:
|
||||
- 分析性能瓶颈:N+1 查询问题
|
||||
- 设计优化方案:使用 JOIN 和预加载
|
||||
|
||||
2. **Coder**:
|
||||
- 优化数据库查询
|
||||
- 添加 Redis 缓存
|
||||
- 更新前端数据获取逻辑
|
||||
|
||||
3. **Tester**:
|
||||
- 性能测试:加载时间从 3s → 300ms
|
||||
- 并发测试:100 用户同时访问
|
||||
- 缓存一致性测试
|
||||
|
||||
4. **Deployer**:
|
||||
- 灰度发布到 10% 用户
|
||||
- 监控性能指标
|
||||
- 全量发布
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **明确任务范围**: 复杂任务交给 Swarm,简单任务直接执行
|
||||
2. **合理设置 max_turns**: 避免 Agent 陷入死循环
|
||||
3. **记录 Handoff 原因**: 便于追溯和调试
|
||||
4. **定期审查轨迹**: 优化 Agent 协作流程
|
||||
5. **利用 Context Variables**: 避免重复传递信息
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
| 问题 | 原因 | 解决方案 |
|
||||
|------|------|----------|
|
||||
| Agent 一直循环 | max_turns 设置过大 | 降低 max_turns,添加明确的 handoff 条件 |
|
||||
| Handoff 失败 | 目标 Agent 未定义 | 检查 swarm.yaml 配置 |
|
||||
| 上下文丢失 | Context Variables 未传递 | 在 handoff 时显式传递 context |
|
||||
| 执行太慢 | 串行执行可并行任务 | 使用 `/swarm parallel` |
|
||||
|
||||
---
|
||||
|
||||
## 与其他 Skills 集成
|
||||
|
||||
- **dev-coding**: Coder Agent 使用 dev-coding 的编码规范
|
||||
- **dev-test**: Tester Agent 使用 dev-test 的测试策略
|
||||
- **ops-tools**: Deployer Agent 使用 ops-tools 进行部署
|
||||
- **ai-proj**: 所有 Agent 使用 ai-proj MCP 进行任务同步
|
||||
|
||||
---
|
||||
|
||||
## 命令速查
|
||||
|
||||
| 命令 | 功能 |
|
||||
|------|------|
|
||||
| `/swarm start <task>` | 启动 Swarm 工作流(从 Architect 开始) |
|
||||
| `/swarm <agent> <task>` | 从指定 Agent 开始 |
|
||||
| `/swarm parallel <tasks>` | 并行执行多个任务 |
|
||||
| `/swarm trace` | 查看执行轨迹 |
|
||||
| `/swarm config` | 显示当前配置 |
|
||||
| `/swarm agents` | 列出所有可用 Agent |
|
||||
| `/swarm stop` | 终止当前 Swarm 执行 |
|
||||
|
||||
---
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [OpenAI Swarm 文档](https://github.com/openai/swarm)
|
||||
- [Multi-Agent Systems 设计模式](https://arxiv.org/abs/2308.00352)
|
||||
- [Claude Code Skills 文档](https://docs.anthropic.com/claude-code/skills)
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "dev-plugin",
|
||||
"description": "Plugin for dev",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,314 +0,0 @@
|
||||
---
|
||||
name: dev
|
||||
description: 软件开发技能组入口。整合架构设计(dev-arch)、编码实现(dev-coding)、测试(dev-test)三个子技能,提供完整的软件开发工作流。支持全栈开发:Go、Vue、React、iOS、Android、小程序等。
|
||||
---
|
||||
|
||||
# 软件开发 Skill (dev)
|
||||
|
||||
## 概述
|
||||
|
||||
dev 是一个技能组入口,整合了软件开发的三个核心阶段:
|
||||
|
||||
| 子技能 | 用途 | 触发词 |
|
||||
|--------|------|--------|
|
||||
| **dev-arch** | 架构设计、技术选型、系统设计 | 架构、设计、技术方案 |
|
||||
| **dev-coding** | 编码实现、功能开发、代码审查 | 编码、开发、实现 |
|
||||
| **dev-test** | 单元测试、集成测试、E2E测试 | 测试、test、覆盖率 |
|
||||
|
||||
---
|
||||
|
||||
## 开发工作流
|
||||
|
||||
```
|
||||
需求分析 → 架构设计 → 编码实现 → 测试验证 → 部署上线
|
||||
↓ ↓ ↓
|
||||
dev-arch dev-coding dev-test
|
||||
```
|
||||
|
||||
### 典型流程
|
||||
|
||||
1. **架构设计** (dev-arch)
|
||||
- 需求分析
|
||||
- 技术选型
|
||||
- 系统设计文档
|
||||
- 架构评审
|
||||
|
||||
2. **编码实现** (dev-coding)
|
||||
- 任务分解
|
||||
- 功能开发
|
||||
- 代码审查
|
||||
- 文档记录
|
||||
|
||||
3. **测试验证** (dev-test)
|
||||
- 单元测试
|
||||
- 集成测试
|
||||
- E2E 测试
|
||||
- 覆盖率分析
|
||||
|
||||
---
|
||||
|
||||
## 支持的项目类型
|
||||
|
||||
### 当前项目生态
|
||||
|
||||
| 项目 | 类型 | 技术栈 |
|
||||
|------|------|--------|
|
||||
| **TWMS** | 仓储物流 | Go + Vue 3 + MySQL |
|
||||
| **AI-Proj** | 项目管理 | Go + React + PostgreSQL + iOS + Android |
|
||||
| **DICIAI** | 进销存SaaS | Go + Vue 3 + MySQL + Android PDA |
|
||||
|
||||
### 技术栈矩阵
|
||||
|
||||
| 端 | 语言/框架 | 工具 |
|
||||
|-----|----------|------|
|
||||
| **后端** | Go (Gin + GORM) | MySQL/PostgreSQL, Redis, Docker |
|
||||
| **Web前端** | Vue 3 / React 18 | TypeScript, Vite/CRA, Ant Design |
|
||||
| **iOS** | Swift + SwiftUI | Xcode, XCTest |
|
||||
| **Android** | Kotlin + Compose | Gradle, Hilt, Room |
|
||||
| **PDA** | Android 原生 | 扫码枪集成, 离线存储 |
|
||||
| **MCP** | TypeScript | Node.js, MCP SDK |
|
||||
|
||||
---
|
||||
|
||||
## ai-proj 任务管理集成
|
||||
|
||||
所有开发工作都通过 ai-proj CLI 进行任务管理:
|
||||
|
||||
### 快速开始
|
||||
|
||||
```bash
|
||||
# 1. 查看待办任务
|
||||
ai-proj task list --status in_progress,todo
|
||||
|
||||
# 2. 启动任务
|
||||
ai-proj task start --id <taskId>
|
||||
|
||||
# 3. 完成任务
|
||||
ai-proj task complete --id <taskId>
|
||||
|
||||
# 4. 记录文档
|
||||
ai-proj task append-doc --id <taskId> --content "实现说明"
|
||||
```
|
||||
|
||||
### 任务分解
|
||||
|
||||
```bash
|
||||
# 创建主任务
|
||||
ai-proj task create --title "功能名称"
|
||||
|
||||
# 创建子任务
|
||||
ai-proj task create --title "架构设计" --parent-id <parentId>
|
||||
ai-proj task create --title "功能开发" --parent-id <parentId>
|
||||
ai-proj task create --title "测试验证" --parent-id <parentId>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常用命令速查
|
||||
|
||||
### Go 后端
|
||||
|
||||
```bash
|
||||
# 构建
|
||||
make build
|
||||
|
||||
# 运行
|
||||
./_output/main --config ./configs/config.yaml
|
||||
|
||||
# 测试
|
||||
make test
|
||||
make cover
|
||||
```
|
||||
|
||||
### Vue 前端
|
||||
|
||||
```bash
|
||||
# 开发
|
||||
npm run dev
|
||||
|
||||
# 构建
|
||||
npm run build:prod
|
||||
|
||||
# 检查
|
||||
npm run lint:eslint
|
||||
```
|
||||
|
||||
### React 前端
|
||||
|
||||
```bash
|
||||
# 开发
|
||||
npm start
|
||||
|
||||
# 构建
|
||||
npm run build
|
||||
|
||||
# 测试
|
||||
npm test
|
||||
npm run test:e2e
|
||||
```
|
||||
|
||||
### iOS
|
||||
|
||||
```bash
|
||||
# 构建
|
||||
xcodebuild -scheme ProjectName -configuration Debug
|
||||
|
||||
# 测试
|
||||
xcodebuild test -scheme ProjectName
|
||||
```
|
||||
|
||||
### Android
|
||||
|
||||
```bash
|
||||
# 构建
|
||||
./gradlew assembleDebug
|
||||
./gradlew assembleRelease
|
||||
|
||||
# 测试
|
||||
./gradlew test
|
||||
./gradlew connectedAndroidTest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Git 工作流
|
||||
|
||||
### 提交规范
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| feat | 新功能 |
|
||||
| fix | Bug 修复 |
|
||||
| docs | 文档 |
|
||||
| refactor | 重构 |
|
||||
| test | 测试 |
|
||||
| chore | 杂项 |
|
||||
|
||||
### 分支策略
|
||||
|
||||
```bash
|
||||
# 功能开发
|
||||
git checkout -b feature/功能名称
|
||||
|
||||
# 提交
|
||||
git commit -m "feat: 功能描述"
|
||||
|
||||
# 推送
|
||||
git push origin feature/功能名称
|
||||
|
||||
# 合并
|
||||
git checkout main
|
||||
git merge feature/功能名称
|
||||
```
|
||||
|
||||
### 双电脑同步 (au-dev / cn-dev)
|
||||
|
||||
```bash
|
||||
# 离开时
|
||||
git add -A
|
||||
git commit -m "WIP: sync from $(hostname)"
|
||||
git push origin $(git branch --show-current)
|
||||
|
||||
# 到达时
|
||||
git fetch origin
|
||||
git pull origin $(git branch --show-current)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker 部署
|
||||
|
||||
### 标准配置
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
build: ./backend
|
||||
ports:
|
||||
- "8080:8080"
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
|
||||
frontend:
|
||||
build: ./frontend
|
||||
ports:
|
||||
- "80:80"
|
||||
|
||||
db:
|
||||
image: mysql:8.0
|
||||
# 或 postgres:15
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
```
|
||||
|
||||
### 常用端口
|
||||
|
||||
| 服务 | 端口 |
|
||||
|------|------|
|
||||
| Backend | 8080 / 9099 |
|
||||
| Frontend | 80 / 3000 |
|
||||
| MySQL | 3306 |
|
||||
| PostgreSQL | 5432 |
|
||||
| Redis | 6379 |
|
||||
|
||||
---
|
||||
|
||||
## 子技能详情
|
||||
|
||||
### dev-arch (架构设计)
|
||||
|
||||
用于系统设计阶段:
|
||||
- 需求分析
|
||||
- 技术选型
|
||||
- 架构设计文档
|
||||
- API 设计
|
||||
- 数据库设计
|
||||
- 架构评审
|
||||
|
||||
### dev-coding (编码实现)
|
||||
|
||||
用于开发实现阶段:
|
||||
- Go 后端开发
|
||||
- Vue/React 前端开发
|
||||
- iOS/Android 移动开发
|
||||
- PDA 应用开发
|
||||
- MCP 桥接开发
|
||||
- 代码审查
|
||||
|
||||
### dev-test (测试)
|
||||
|
||||
用于测试验证阶段:
|
||||
- 单元测试
|
||||
- 集成测试
|
||||
- E2E 测试
|
||||
- UI 测试
|
||||
- 覆盖率分析
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **任务驱动** - 使用 ai-proj 管理所有开发任务
|
||||
2. **设计先行** - 复杂功能先设计后编码
|
||||
3. **分层清晰** - Controller → Service → Repository
|
||||
4. **小步提交** - 频繁提交,每次做一件事
|
||||
5. **测试覆盖** - 核心逻辑必须有测试
|
||||
6. **文档同步** - 代码变更同步更新文档
|
||||
7. **代码审查** - 重要变更必须审查
|
||||
|
||||
---
|
||||
|
||||
## 何时使用哪个子技能
|
||||
|
||||
| 场景 | 推荐技能 |
|
||||
|------|----------|
|
||||
| 新功能设计 | dev-arch |
|
||||
| 技术方案评审 | dev-arch |
|
||||
| 功能开发实现 | dev-coding |
|
||||
| Bug 修复 | dev-coding |
|
||||
| 编写测试 | dev-test |
|
||||
| 测试覆盖率提升 | dev-test |
|
||||
| 代码审查 | dev-coding |
|
||||
| 性能优化 | dev-arch + dev-coding |
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "finishing-a-development-branch-plugin",
|
||||
"description": "Plugin for finishing-a-development-branch",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
---
|
||||
name: finishing-a-development-branch
|
||||
description: Use when implementation is complete and all tests pass - verifies and creates PR
|
||||
---
|
||||
|
||||
# Finishing a Development Branch
|
||||
|
||||
## Overview
|
||||
|
||||
Verify tests pass, then push and create PR.
|
||||
|
||||
**Core principle:** Verify tests → Create PR → Done.
|
||||
|
||||
**Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work."
|
||||
|
||||
## The Process
|
||||
|
||||
### Step 1: Verify Tests
|
||||
|
||||
**Before creating PR, verify tests pass:**
|
||||
|
||||
```bash
|
||||
# Run project's test suite
|
||||
npm test / cargo test / pytest / go test ./... / mvn test
|
||||
```
|
||||
|
||||
**If tests fail:**
|
||||
```
|
||||
Tests failing (<N> failures). Must fix before completing:
|
||||
|
||||
[Show failures]
|
||||
|
||||
Cannot proceed with PR until tests pass.
|
||||
```
|
||||
|
||||
Stop. Fix tests first.
|
||||
|
||||
**If tests pass:** Continue to Step 2.
|
||||
|
||||
### Step 2: Push and Create PR
|
||||
|
||||
Use the `/pr create` command which will:
|
||||
1. **Check for existing PR first** - avoids duplicates
|
||||
2. If PR exists: Report existing PR URL and skip
|
||||
3. If no PR: Analyze commits, generate title/description, push, create PR
|
||||
|
||||
```bash
|
||||
/pr create
|
||||
```
|
||||
|
||||
**Duplicate prevention:** The `/pr create` command checks for existing open PRs on the current branch before creating a new one.
|
||||
|
||||
Report the PR URL when complete (whether existing or newly created).
|
||||
|
||||
### Step 3: Cleanup Worktree (if applicable)
|
||||
|
||||
Check if working in a worktree:
|
||||
```bash
|
||||
git worktree list | grep $(git branch --show-current)
|
||||
```
|
||||
|
||||
If yes, ask user:
|
||||
```
|
||||
Worktree at <path>. Remove it now? (y/n)
|
||||
```
|
||||
|
||||
If confirmed:
|
||||
```bash
|
||||
git worktree remove <worktree-path>
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```
|
||||
Tests Pass?
|
||||
↓ yes
|
||||
/pr create
|
||||
↓
|
||||
PR URL returned
|
||||
↓
|
||||
Cleanup worktree (optional)
|
||||
↓
|
||||
Done
|
||||
```
|
||||
|
||||
## Red Flags
|
||||
|
||||
**Never:**
|
||||
- Create PR with failing tests
|
||||
- Skip test verification
|
||||
- Force-push without explicit request
|
||||
|
||||
**Always:**
|
||||
- Verify tests before creating PR
|
||||
- Use `/pr create` for consistent PR format
|
||||
- Report the PR URL
|
||||
|
||||
## Integration
|
||||
|
||||
**Called by:**
|
||||
- **executing-plans** (Step 6) - After all batches complete
|
||||
|
||||
**Uses:**
|
||||
- **/pr create** - For pushing and PR creation
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "frontend-design-plugin",
|
||||
"description": "Plugin for frontend-design",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,695 +0,0 @@
|
||||
---
|
||||
name: frontend-design
|
||||
description: Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
|
||||
arguments: [component|page|storybook] <description>
|
||||
---
|
||||
|
||||
# Frontend Design 前端设计技能
|
||||
|
||||
创建高质量、有设计感的前端界面和组件,支持 Storybook 组件开发。
|
||||
|
||||
---
|
||||
|
||||
## 命令格式
|
||||
|
||||
| 命令 | 功能 | 示例 |
|
||||
|------|------|------|
|
||||
| `/frontend-design component <描述>` | 创建 React/Vue 组件 | `/frontend-design component 产品卡片` |
|
||||
| `/frontend-design page <描述>` | 创建完整页面 | `/frontend-design page 登录页` |
|
||||
| `/frontend-design storybook <描述>` | 创建带 Storybook 的组件 | `/frontend-design storybook 按钮组件` |
|
||||
|
||||
---
|
||||
|
||||
## 设计原则
|
||||
|
||||
### 1. 设计思维先行
|
||||
|
||||
在编码前,明确以下问题:
|
||||
|
||||
- **目的**:这个界面解决什么问题?谁在使用?
|
||||
- **调性**:选择一个明确的美学方向
|
||||
- **差异化**:什么让这个设计令人难忘?
|
||||
|
||||
### 2. 美学方向选择
|
||||
|
||||
| 风格 | 特点 | 适用场景 |
|
||||
|------|------|----------|
|
||||
| 极简主义 | 大量留白、精炼元素 | 工具类、专业平台 |
|
||||
| 现代商务 | 清晰层次、专业配色 | 企业官网、B2B |
|
||||
| 活力年轻 | 鲜艳色彩、动感动画 | 消费品、社交 |
|
||||
| 奢华精致 | 深色调、金属质感 | 高端品牌、金融 |
|
||||
| 自然有机 | 柔和曲线、自然色系 | 健康、环保 |
|
||||
| 复古怀旧 | 经典字体、做旧质感 | 文化、艺术 |
|
||||
| 未来科技 | 渐变、玻璃拟态 | 科技、创新 |
|
||||
|
||||
### 3. 避免的设计陷阱
|
||||
|
||||
**禁止使用**:
|
||||
- 过度使用的字体:Inter、Roboto、Arial
|
||||
- 陈词滥调的配色:紫色渐变白底
|
||||
- 千篇一律的布局
|
||||
- 缺乏个性的通用组件
|
||||
|
||||
**应该追求**:
|
||||
- 独特的字体组合
|
||||
- 有意图的配色方案
|
||||
- 打破常规的布局
|
||||
- 有记忆点的细节
|
||||
|
||||
---
|
||||
|
||||
## Storybook 组件开发
|
||||
|
||||
### 项目结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/
|
||||
│ ├── Button/
|
||||
│ │ ├── Button.tsx
|
||||
│ │ ├── Button.stories.tsx
|
||||
│ │ ├── Button.module.css
|
||||
│ │ └── index.ts
|
||||
│ ├── Card/
|
||||
│ │ ├── Card.tsx
|
||||
│ │ ├── Card.stories.tsx
|
||||
│ │ ├── Card.module.css
|
||||
│ │ └── index.ts
|
||||
│ └── index.ts
|
||||
├── styles/
|
||||
│ ├── variables.css
|
||||
│ ├── typography.css
|
||||
│ └── animations.css
|
||||
└── .storybook/
|
||||
├── main.ts
|
||||
└── preview.ts
|
||||
```
|
||||
|
||||
### 组件模板
|
||||
|
||||
#### 1. 组件文件 (Component.tsx)
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
import styles from './Component.module.css';
|
||||
|
||||
export interface ComponentProps {
|
||||
/** 组件变体 */
|
||||
variant?: 'primary' | 'secondary' | 'outline';
|
||||
/** 尺寸 */
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
/** 是否禁用 */
|
||||
disabled?: boolean;
|
||||
/** 子元素 */
|
||||
children: React.ReactNode;
|
||||
/** 点击事件 */
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const Component: React.FC<ComponentProps> = ({
|
||||
variant = 'primary',
|
||||
size = 'md',
|
||||
disabled = false,
|
||||
children,
|
||||
onClick,
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={`${styles.component} ${styles[variant]} ${styles[size]}`}
|
||||
data-disabled={disabled}
|
||||
onClick={disabled ? undefined : onClick}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
#### 2. Storybook Stories (Component.stories.tsx)
|
||||
|
||||
```tsx
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { Component } from './Component';
|
||||
|
||||
const meta: Meta<typeof Component> = {
|
||||
title: 'Components/Component',
|
||||
component: Component,
|
||||
tags: ['autodocs'],
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
docs: {
|
||||
description: {
|
||||
component: '组件描述文档',
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
variant: {
|
||||
control: 'select',
|
||||
options: ['primary', 'secondary', 'outline'],
|
||||
description: '组件变体样式',
|
||||
},
|
||||
size: {
|
||||
control: 'radio',
|
||||
options: ['sm', 'md', 'lg'],
|
||||
description: '组件尺寸',
|
||||
},
|
||||
disabled: {
|
||||
control: 'boolean',
|
||||
description: '是否禁用',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Component>;
|
||||
|
||||
/** 默认状态 */
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
children: '默认组件',
|
||||
},
|
||||
};
|
||||
|
||||
/** 主要变体 */
|
||||
export const Primary: Story = {
|
||||
args: {
|
||||
variant: 'primary',
|
||||
children: '主要按钮',
|
||||
},
|
||||
};
|
||||
|
||||
/** 次要变体 */
|
||||
export const Secondary: Story = {
|
||||
args: {
|
||||
variant: 'secondary',
|
||||
children: '次要按钮',
|
||||
},
|
||||
};
|
||||
|
||||
/** 不同尺寸 */
|
||||
export const Sizes: Story = {
|
||||
render: () => (
|
||||
<div style={{ display: 'flex', gap: '1rem', alignItems: 'center' }}>
|
||||
<Component size="sm">小号</Component>
|
||||
<Component size="md">中号</Component>
|
||||
<Component size="lg">大号</Component>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
|
||||
/** 禁用状态 */
|
||||
export const Disabled: Story = {
|
||||
args: {
|
||||
disabled: true,
|
||||
children: '禁用状态',
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
#### 3. 样式文件 (Component.module.css)
|
||||
|
||||
```css
|
||||
.component {
|
||||
/* 基础样式 */
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: var(--radius-md);
|
||||
font-family: var(--font-sans);
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* 变体 */
|
||||
.primary {
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.primary:hover {
|
||||
background: var(--color-primary-dark);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px var(--color-primary-shadow);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background: var(--color-secondary);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.outline {
|
||||
background: transparent;
|
||||
border: 2px solid var(--color-border);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
/* 尺寸 */
|
||||
.sm {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.md {
|
||||
padding: 0.75rem 1.5rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.lg {
|
||||
padding: 1rem 2rem;
|
||||
font-size: 1.125rem;
|
||||
}
|
||||
|
||||
/* 状态 */
|
||||
[data-disabled="true"] {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 设计系统变量
|
||||
|
||||
### CSS 变量模板
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* 颜色 */
|
||||
--color-primary: #0066ff;
|
||||
--color-primary-dark: #0052cc;
|
||||
--color-primary-light: #4d94ff;
|
||||
--color-primary-shadow: rgba(0, 102, 255, 0.25);
|
||||
|
||||
--color-secondary: #f0f4f8;
|
||||
--color-accent: #ff6b35;
|
||||
|
||||
--color-text: #1a1a2e;
|
||||
--color-text-muted: #64748b;
|
||||
--color-text-inverse: #ffffff;
|
||||
|
||||
--color-background: #ffffff;
|
||||
--color-surface: #f8fafc;
|
||||
--color-border: #e2e8f0;
|
||||
|
||||
--color-success: #10b981;
|
||||
--color-warning: #f59e0b;
|
||||
--color-error: #ef4444;
|
||||
|
||||
/* 字体 */
|
||||
--font-sans: 'Plus Jakarta Sans', system-ui, sans-serif;
|
||||
--font-display: 'Clash Display', var(--font-sans);
|
||||
--font-mono: 'JetBrains Mono', monospace;
|
||||
|
||||
/* 字号 */
|
||||
--text-xs: 0.75rem;
|
||||
--text-sm: 0.875rem;
|
||||
--text-base: 1rem;
|
||||
--text-lg: 1.125rem;
|
||||
--text-xl: 1.25rem;
|
||||
--text-2xl: 1.5rem;
|
||||
--text-3xl: 2rem;
|
||||
--text-4xl: 2.5rem;
|
||||
|
||||
/* 间距 */
|
||||
--space-1: 0.25rem;
|
||||
--space-2: 0.5rem;
|
||||
--space-3: 0.75rem;
|
||||
--space-4: 1rem;
|
||||
--space-6: 1.5rem;
|
||||
--space-8: 2rem;
|
||||
--space-12: 3rem;
|
||||
--space-16: 4rem;
|
||||
|
||||
/* 圆角 */
|
||||
--radius-sm: 0.25rem;
|
||||
--radius-md: 0.5rem;
|
||||
--radius-lg: 1rem;
|
||||
--radius-xl: 1.5rem;
|
||||
--radius-full: 9999px;
|
||||
|
||||
/* 阴影 */
|
||||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
||||
|
||||
/* 动画 */
|
||||
--duration-fast: 150ms;
|
||||
--duration-normal: 300ms;
|
||||
--duration-slow: 500ms;
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
/* 暗色主题 */
|
||||
[data-theme="dark"] {
|
||||
--color-text: #f1f5f9;
|
||||
--color-text-muted: #94a3b8;
|
||||
--color-background: #0f172a;
|
||||
--color-surface: #1e293b;
|
||||
--color-border: #334155;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常用组件示例
|
||||
|
||||
### 1. 产品卡片 (ProductCard)
|
||||
|
||||
```tsx
|
||||
// ProductCard.tsx
|
||||
import React from 'react';
|
||||
import styles from './ProductCard.module.css';
|
||||
|
||||
export interface ProductCardProps {
|
||||
image: string;
|
||||
title: string;
|
||||
location: string;
|
||||
rating: number;
|
||||
reviewCount: number;
|
||||
price: number;
|
||||
originalPrice?: number;
|
||||
tags?: string[];
|
||||
onAddToCart?: () => void;
|
||||
}
|
||||
|
||||
export const ProductCard: React.FC<ProductCardProps> = ({
|
||||
image,
|
||||
title,
|
||||
location,
|
||||
rating,
|
||||
reviewCount,
|
||||
price,
|
||||
originalPrice,
|
||||
tags = [],
|
||||
onAddToCart,
|
||||
}) => {
|
||||
return (
|
||||
<article className={styles.card}>
|
||||
<div className={styles.imageWrapper}>
|
||||
<img src={image} alt={title} className={styles.image} />
|
||||
{tags.length > 0 && (
|
||||
<div className={styles.tags}>
|
||||
{tags.map((tag) => (
|
||||
<span key={tag} className={styles.tag} data-tag={tag}>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={styles.content}>
|
||||
<h3 className={styles.title}>{title}</h3>
|
||||
<p className={styles.location}>📍 {location}</p>
|
||||
|
||||
<div className={styles.rating}>
|
||||
<span className={styles.stars}>⭐ {rating.toFixed(1)}</span>
|
||||
<span className={styles.reviewCount}>({reviewCount}条评价)</span>
|
||||
</div>
|
||||
|
||||
<div className={styles.priceRow}>
|
||||
<div className={styles.price}>
|
||||
<span className={styles.currency}>¥</span>
|
||||
<span className={styles.amount}>{price}</span>
|
||||
<span className={styles.suffix}>起</span>
|
||||
</div>
|
||||
{originalPrice && (
|
||||
<span className={styles.originalPrice}>¥{originalPrice}</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button className={styles.addButton} onClick={onAddToCart}>
|
||||
加入购物车
|
||||
</button>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
```tsx
|
||||
// ProductCard.stories.tsx
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { ProductCard } from './ProductCard';
|
||||
|
||||
const meta: Meta<typeof ProductCard> = {
|
||||
title: 'Components/ProductCard',
|
||||
component: ProductCard,
|
||||
tags: ['autodocs'],
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
backgrounds: {
|
||||
default: 'light',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof ProductCard>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
image: 'https://images.unsplash.com/photo-1494947665470-20322015e3a8',
|
||||
title: '袋鼠岛一日游',
|
||||
location: '阿德莱德出发',
|
||||
rating: 4.8,
|
||||
reviewCount: 126,
|
||||
price: 389,
|
||||
tags: ['热卖', '含午餐'],
|
||||
},
|
||||
};
|
||||
|
||||
export const WithDiscount: Story = {
|
||||
args: {
|
||||
...Default.args,
|
||||
originalPrice: 499,
|
||||
tags: ['特惠', '限时'],
|
||||
},
|
||||
};
|
||||
|
||||
export const Grid: Story = {
|
||||
render: () => (
|
||||
<div style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(3, 300px)',
|
||||
gap: '1.5rem'
|
||||
}}>
|
||||
<ProductCard
|
||||
image="https://images.unsplash.com/photo-1494947665470-20322015e3a8"
|
||||
title="袋鼠岛一日游"
|
||||
location="阿德莱德出发"
|
||||
rating={4.8}
|
||||
reviewCount={126}
|
||||
price={389}
|
||||
tags={['热卖']}
|
||||
/>
|
||||
<ProductCard
|
||||
image="https://images.unsplash.com/photo-1506905925346-21bda4d32df4"
|
||||
title="巴罗莎谷酒庄之旅"
|
||||
location="阿德莱德出发"
|
||||
rating={4.9}
|
||||
reviewCount={89}
|
||||
price={299}
|
||||
originalPrice={399}
|
||||
tags={['特惠', '含品酒']}
|
||||
/>
|
||||
<ProductCard
|
||||
image="https://images.unsplash.com/photo-1540202403-b7abd6747a18"
|
||||
title="海豚巡航体验"
|
||||
location="格雷尔海滩"
|
||||
rating={4.7}
|
||||
reviewCount={234}
|
||||
price={159}
|
||||
tags={['亲子']}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
```
|
||||
|
||||
### 2. 按钮组件 (Button)
|
||||
|
||||
```tsx
|
||||
// Button.tsx
|
||||
import React from 'react';
|
||||
import styles from './Button.module.css';
|
||||
|
||||
export interface ButtonProps {
|
||||
variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
|
||||
size?: 'sm' | 'md' | 'lg';
|
||||
fullWidth?: boolean;
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
leftIcon?: React.ReactNode;
|
||||
rightIcon?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const Button: React.FC<ButtonProps> = ({
|
||||
variant = 'primary',
|
||||
size = 'md',
|
||||
fullWidth = false,
|
||||
loading = false,
|
||||
disabled = false,
|
||||
leftIcon,
|
||||
rightIcon,
|
||||
children,
|
||||
onClick,
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={`
|
||||
${styles.button}
|
||||
${styles[variant]}
|
||||
${styles[size]}
|
||||
${fullWidth ? styles.fullWidth : ''}
|
||||
`}
|
||||
disabled={disabled || loading}
|
||||
onClick={onClick}
|
||||
>
|
||||
{loading ? (
|
||||
<span className={styles.spinner} />
|
||||
) : (
|
||||
<>
|
||||
{leftIcon && <span className={styles.icon}>{leftIcon}</span>}
|
||||
<span>{children}</span>
|
||||
{rightIcon && <span className={styles.icon}>{rightIcon}</span>}
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Storybook 配置
|
||||
|
||||
### .storybook/main.ts
|
||||
|
||||
```ts
|
||||
import type { StorybookConfig } from '@storybook/react-vite';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-interactions',
|
||||
'@storybook/addon-a11y',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
options: {},
|
||||
},
|
||||
docs: {
|
||||
autodocs: 'tag',
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
```
|
||||
|
||||
### .storybook/preview.ts
|
||||
|
||||
```ts
|
||||
import type { Preview } from '@storybook/react';
|
||||
import '../src/styles/variables.css';
|
||||
import '../src/styles/typography.css';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/,
|
||||
},
|
||||
},
|
||||
backgrounds: {
|
||||
default: 'light',
|
||||
values: [
|
||||
{ name: 'light', value: '#ffffff' },
|
||||
{ name: 'gray', value: '#f8fafc' },
|
||||
{ name: 'dark', value: '#0f172a' },
|
||||
],
|
||||
},
|
||||
},
|
||||
globalTypes: {
|
||||
theme: {
|
||||
description: 'Global theme for components',
|
||||
defaultValue: 'light',
|
||||
toolbar: {
|
||||
title: 'Theme',
|
||||
icon: 'circlehollow',
|
||||
items: ['light', 'dark'],
|
||||
dynamicTitle: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 快速启动命令
|
||||
|
||||
### 创建新组件
|
||||
|
||||
```bash
|
||||
# 创建组件目录
|
||||
mkdir -p src/components/ComponentName
|
||||
|
||||
# 创建文件
|
||||
touch src/components/ComponentName/{ComponentName.tsx,ComponentName.stories.tsx,ComponentName.module.css,index.ts}
|
||||
```
|
||||
|
||||
### 安装 Storybook
|
||||
|
||||
```bash
|
||||
# 初始化 Storybook
|
||||
npx storybook@latest init
|
||||
|
||||
# 安装额外插件
|
||||
npm install -D @storybook/addon-a11y @storybook/addon-interactions
|
||||
|
||||
# 启动 Storybook
|
||||
npm run storybook
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 设计检查清单
|
||||
|
||||
### 组件质量检查
|
||||
|
||||
- [ ] Props 接口定义完整,带 JSDoc 注释
|
||||
- [ ] 支持必要的变体(variant)和尺寸(size)
|
||||
- [ ] 处理禁用和加载状态
|
||||
- [ ] 支持自定义 className
|
||||
- [ ] 键盘可访问性
|
||||
- [ ] 屏幕阅读器友好
|
||||
|
||||
### Storybook 质量检查
|
||||
|
||||
- [ ] 所有变体都有对应 Story
|
||||
- [ ] argTypes 配置完整
|
||||
- [ ] 包含组件文档描述
|
||||
- [ ] 交互状态可测试
|
||||
- [ ] 响应式展示
|
||||
|
||||
### 视觉质量检查
|
||||
|
||||
- [ ] 字体选择有特色
|
||||
- [ ] 配色方案协调
|
||||
- [ ] 动画流畅自然
|
||||
- [ ] 间距一致
|
||||
- [ ] 暗色主题支持
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "gitea-plugin",
|
||||
"description": "Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
#!/bin/bash
|
||||
# gitea-runs — Gitea Actions CLI helper
|
||||
# Usage:
|
||||
# gitea-runs List recent runs
|
||||
# gitea-runs list [limit] List recent runs (default 10)
|
||||
# gitea-runs view <run_number> View run details & jobs
|
||||
# gitea-runs open [run_number] Open run in browser
|
||||
# gitea-runs workflows List workflows
|
||||
# gitea-runs dispatch <wf> [ref] Trigger a workflow dispatch
|
||||
# gitea-runs help Show this help
|
||||
|
||||
set -e
|
||||
|
||||
# Config from tea CLI
|
||||
TEA_CONFIG="${XDG_CONFIG_HOME:-$HOME/Library/Application Support}/tea/config.yml"
|
||||
if [ ! -f "$TEA_CONFIG" ]; then
|
||||
TEA_CONFIG="$HOME/.config/tea/config.yml"
|
||||
fi
|
||||
|
||||
# Parse tea config (nested under logins)
|
||||
GITEA_URL=$(grep 'url:' "$TEA_CONFIG" | head -1 | awk '{print $NF}')
|
||||
GITEA_TOKEN=$(grep 'token:' "$TEA_CONFIG" | head -1 | awk '{print $NF}')
|
||||
|
||||
# Detect repo from git remote
|
||||
REPO=$(git remote get-url origin 2>/dev/null | sed 's|.*gitea.pipexerp.com[:/]*||;s|\.git$||;s|^10022/||')
|
||||
if [ -z "$REPO" ]; then
|
||||
echo "Error: not in a git repo or remote not configured"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
API="$GITEA_URL/api/v1"
|
||||
AUTH="Authorization: token $GITEA_TOKEN"
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
cmd_dispatch() {
|
||||
local workflow="${1:-}"
|
||||
local ref="${2:-main}"
|
||||
if [ -z "$workflow" ]; then
|
||||
echo "Usage: gitea-runs dispatch <workflow> [ref]"
|
||||
echo ""
|
||||
echo "Available workflows:"
|
||||
curl -s -H "$AUTH" "$API/repos/$REPO/actions/workflows" 2>/dev/null \
|
||||
| python3 -c "
|
||||
import json, sys
|
||||
data = json.load(sys.stdin)
|
||||
for w in data.get('workflows', []):
|
||||
print(f\" {w['id']:30s} {w['name']}\")
|
||||
" 2>/dev/null
|
||||
return
|
||||
fi
|
||||
|
||||
local http_code
|
||||
http_code=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "$AUTH" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "$API/repos/$REPO/actions/workflows/$workflow/dispatches" \
|
||||
-d "{\"ref\":\"$ref\"}" 2>/dev/null)
|
||||
|
||||
if [ "$http_code" = "204" ]; then
|
||||
echo -e "${GREEN}✓${NC} Dispatched workflow: $workflow (ref: $ref)"
|
||||
echo " View: $GITEA_URL/$REPO/actions"
|
||||
else
|
||||
echo -e "${RED}✗${NC} Failed to dispatch (HTTP $http_code)"
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_workflows() {
|
||||
echo -e "${CYAN}Workflows for $REPO${NC}"
|
||||
echo ""
|
||||
curl -s -H "$AUTH" "$API/repos/$REPO/actions/workflows" 2>/dev/null \
|
||||
| python3 -c "
|
||||
import json, sys
|
||||
data = json.load(sys.stdin)
|
||||
for w in data.get('workflows', []):
|
||||
state = '✓' if w['state'] == 'active' else '✗'
|
||||
print(f\" {state} {w['id']:30s} {w['name']}\")
|
||||
" 2>/dev/null
|
||||
}
|
||||
|
||||
cmd_list() {
|
||||
local limit="${1:-10}"
|
||||
echo -e "${CYAN}Recent runs for $REPO${NC}"
|
||||
echo ""
|
||||
curl -s -H "$AUTH" "$API/repos/$REPO/actions/runs?limit=$limit" 2>/dev/null \
|
||||
| python3 -c "
|
||||
import json, sys
|
||||
limit = $limit
|
||||
data = json.load(sys.stdin)
|
||||
for r in data.get('workflow_runs', [])[:limit]:
|
||||
status = r.get('status', '?')
|
||||
num = r.get('run_number', 0)
|
||||
title = r.get('display_title', '')[:60]
|
||||
wf = r.get('path', '')
|
||||
wf = wf.split('@')[0] if '@' in wf else wf
|
||||
icon = {'success':'\u2713','completed':'\u2713','failure':'\u2717','cancelled':'\u2717','in_progress':'\u27f3','running':'\u27f3','queued':'\u25cc','waiting':'\u25cc'}.get(status, '?')
|
||||
color = {'success':'\033[0;32m','completed':'\033[0;32m','failure':'\033[0;31m','cancelled':'\033[0;31m','in_progress':'\033[0;33m','running':'\033[0;33m'}.get(status, '\033[0;37m')
|
||||
print(f\"{color}{icon}\033[0m #{num:<4} {status:<12} {wf:<20} {title}\")
|
||||
" 2>/dev/null
|
||||
}
|
||||
|
||||
cmd_view() {
|
||||
local run_number="${1:-}"
|
||||
if [ -z "$run_number" ]; then
|
||||
echo "Usage: gitea-runs view <run_number>"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Find run by run_number (API uses internal id, html uses run_number)
|
||||
local run_data
|
||||
run_data=$(curl -s -H "$AUTH" "$API/repos/$REPO/actions/runs?limit=50" 2>/dev/null \
|
||||
| python3 -c "
|
||||
import json, sys
|
||||
data = json.load(sys.stdin)
|
||||
for r in data.get('workflow_runs', []):
|
||||
if r['run_number'] == $run_number:
|
||||
print(json.dumps(r))
|
||||
break
|
||||
" 2>/dev/null)
|
||||
|
||||
if [ -z "$run_data" ]; then
|
||||
echo -e "${RED}✗${NC} Run #$run_number not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local run_id
|
||||
run_id=$(echo "$run_data" | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
|
||||
|
||||
# Print run info
|
||||
echo "$run_data" | python3 -c "
|
||||
import json, sys
|
||||
r = json.load(sys.stdin)
|
||||
status = r.get('status', '?')
|
||||
icon = {'success':'\u2713','failure':'\u2717','in_progress':'\u27f3','queued':'\u25cc'}.get(status, '?')
|
||||
color = {'success':'\033[0;32m','failure':'\033[0;31m','in_progress':'\033[0;33m'}.get(status, '\033[0;37m')
|
||||
print(f\"{color}{icon} Run #{r.get('run_number',0)} \u2014 {status}\033[0m\")
|
||||
print(f\" Title: {r.get('display_title','')}\")
|
||||
print(f\" Event: {r.get('event','')}\")
|
||||
print(f\" Branch: {r.get('head_branch','')}\")
|
||||
print(f\" Commit: {r.get('head_sha','')[:8]}\")
|
||||
print(f\" Actor: {r.get('actor',{}).get('login','')}\")
|
||||
wf = r.get('path', '')
|
||||
wf = wf.split('@')[0] if '@' in wf else wf
|
||||
print(f\" Workflow: {wf}\")
|
||||
" 2>/dev/null
|
||||
|
||||
# Print jobs
|
||||
echo ""
|
||||
echo -e "${CYAN}Jobs:${NC}"
|
||||
curl -s -H "$AUTH" "$API/repos/$REPO/actions/runs/$run_id/jobs" 2>/dev/null \
|
||||
| python3 -c "
|
||||
import json, sys
|
||||
from datetime import datetime
|
||||
data = json.load(sys.stdin)
|
||||
for j in data.get('jobs', []):
|
||||
status = j.get('status', '?')
|
||||
icon = {'success':'\u2713','failure':'\u2717','in_progress':'\u27f3','queued':'\u25cc','waiting':'\u25cc'}.get(status, '?')
|
||||
color = {'success':'\033[0;32m','failure':'\033[0;31m','in_progress':'\033[0;33m'}.get(status, '\033[0;37m')
|
||||
runner = j.get('runner_name', '-')
|
||||
started = j.get('started_at', '')[:19].replace('T', ' ')
|
||||
completed = j.get('completed_at', '')[:19].replace('T', ' ')
|
||||
duration = ''
|
||||
if completed and not completed.startswith('1970'):
|
||||
try:
|
||||
d = datetime.fromisoformat(completed) - datetime.fromisoformat(started)
|
||||
duration = f' ({int(d.total_seconds())}s)'
|
||||
except: pass
|
||||
print(f\" {color}{icon}\033[0m {j.get('name',''):<30} {status:<12} runner: {runner}{duration}\")
|
||||
" 2>/dev/null
|
||||
}
|
||||
|
||||
cmd_open() {
|
||||
local run_id="${1:-}"
|
||||
local url="$GITEA_URL/$REPO/actions"
|
||||
if [ -n "$run_id" ]; then
|
||||
url="$url/runs/$run_id"
|
||||
fi
|
||||
echo "Opening: $url"
|
||||
open "$url" 2>/dev/null || xdg-open "$url" 2>/dev/null || echo "$url"
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
echo "gitea-runs — Gitea Actions CLI helper"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " gitea-runs List recent runs"
|
||||
echo " gitea-runs list [limit] List recent runs (default 10)"
|
||||
echo " gitea-runs view <run_number> View run details & jobs"
|
||||
echo " gitea-runs open [run_number] Open run in browser"
|
||||
echo " gitea-runs workflows List workflows"
|
||||
echo " gitea-runs dispatch <wf> [ref] Trigger a workflow dispatch"
|
||||
echo " gitea-runs help Show this help"
|
||||
echo ""
|
||||
echo "Repo: $REPO"
|
||||
echo "Gitea: $GITEA_URL"
|
||||
}
|
||||
|
||||
# Main
|
||||
case "${1:-}" in
|
||||
list|ls) shift; cmd_list "$@" ;;
|
||||
view|v) shift; cmd_view "$@" ;;
|
||||
dispatch) shift; cmd_dispatch "$@" ;;
|
||||
workflows|wf) cmd_workflows ;;
|
||||
open|o) shift; cmd_open "$@" ;;
|
||||
help|--help|-h) cmd_help ;;
|
||||
"") cmd_list ;;
|
||||
*) cmd_view "$1" ;;
|
||||
esac
|
||||
@@ -1,281 +0,0 @@
|
||||
---
|
||||
name: gitea
|
||||
description: Gitea 代码托管与 CI/CD 管理。用于 Gitea Actions workflow 管理、Runner 管理、PR 操作、仓库配置。当用户提到 Gitea、Actions、Runner、CI/CD workflow、PR 检查相关任务时自动激活。
|
||||
---
|
||||
|
||||
# Gitea Skill
|
||||
|
||||
Gitea 代码托管平台管理,覆盖 Actions CI/CD、Runner、PR、仓库配置。
|
||||
|
||||
## 服务器信息
|
||||
|
||||
| 服务 | 地址 | SSH |
|
||||
|------|------|-----|
|
||||
| Gitea Web | https://gitea.pipexerp.com | — |
|
||||
| Gitea SSH | gitea.pipexerp.com:10022 | `ssh -i ~/.ssh/id_ed25519 git@gitea.pipexerp.com -p 10022` |
|
||||
| Gitea 服务器 | 123.56.89.187 | `ssh -i ~/.ssh/tools.pem root@123.56.89.187` |
|
||||
| Runner 服务器 | 101.200.136.200 (Jenkins 服务器) | `ssh -i ~/.ssh/tools.pem root@101.200.136.200` |
|
||||
|
||||
## API 访问
|
||||
|
||||
```bash
|
||||
# Gitea API Token (仓库级)
|
||||
GITEA_TOKEN="483a2b65219625ee382eb6d023cda39238c32e24"
|
||||
|
||||
# 通用请求格式
|
||||
curl -s "https://gitea.pipexerp.com/api/v1/repos/pipexerp/<repo>/..." \
|
||||
-H "Authorization: token $GITEA_TOKEN"
|
||||
```
|
||||
|
||||
### 常用 API
|
||||
|
||||
| 操作 | 方法 | 端点 |
|
||||
|------|------|------|
|
||||
| 创建 PR | POST | `/repos/{owner}/{repo}/pulls` |
|
||||
| 更新 PR | PATCH | `/repos/{owner}/{repo}/pulls/{id}` |
|
||||
| 列出 Runs | GET | `/repos/{owner}/{repo}/actions/runs` |
|
||||
| Run 详情 | GET | `/repos/{owner}/{repo}/actions/runs/{id}` |
|
||||
| Job 详情 | GET | `/repos/{owner}/{repo}/actions/runs/{id}/jobs` |
|
||||
| 手动触发 Workflow | POST | `/repos/{owner}/{repo}/actions/workflows/{file}/dispatches` body: `{"ref":"main"}` |
|
||||
| 获取 Runner Token | POST | `/repos/{owner}/{repo}/actions/runners/registration-token` |
|
||||
| 添加 Secret | PUT | `/repos/{owner}/{repo}/actions/secrets/{name}` body: `{"data":"value"}` |
|
||||
| 删除 Run(仅已完成)| DELETE | `/repos/{owner}/{repo}/actions/runs/{id}` |
|
||||
|
||||
**注意**: Gitea 1.25 **不支持**通过 API cancel 正在排队/运行的 run。
|
||||
|
||||
## 仓库
|
||||
|
||||
| 仓库 | 地址 | 主分支 |
|
||||
|------|------|--------|
|
||||
| coolbuy-paas | pipexerp/coolbuy-paas | main |
|
||||
| dotfiles | huangjun/dotfiles | main |
|
||||
| claude-marketplace | huangjun/claude-marketplace | main |
|
||||
|
||||
## Actions Runners
|
||||
|
||||
### 主 Runner (lint/test/e2e)
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 名称 | jenkins-runner |
|
||||
| 配置 | `/opt/act_runner/config.yaml` |
|
||||
| Capacity | 3 |
|
||||
| Labels | `ubuntu-latest`, `ubuntu-22.04`, `ubuntu-20.04` |
|
||||
| 进程 | `/usr/local/bin/act_runner daemon --config /opt/act_runner/config.yaml` |
|
||||
|
||||
### Deploy Runner (staging 部署专用)
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 名称 | deploy-runner |
|
||||
| 配置 | `/opt/act_runner_deploy/config.yaml` |
|
||||
| Capacity | 1 |
|
||||
| Labels | `deploy:host` |
|
||||
| PID | `/opt/act_runner_deploy/runner.pid` |
|
||||
| 日志 | `/opt/act_runner_deploy/runner.log` |
|
||||
| 启动 | `cd /opt/act_runner_deploy && nohup act_runner daemon --config config.yaml > runner.log 2>&1 &` |
|
||||
|
||||
### 注册新 Runner
|
||||
|
||||
```bash
|
||||
# 1. 获取 registration token
|
||||
curl -s -X POST "https://gitea.pipexerp.com/api/v1/repos/pipexerp/coolbuy-paas/actions/runners/registration-token" \
|
||||
-H "Authorization: token $GITEA_TOKEN"
|
||||
|
||||
# 2. SSH 到 runner 服务器
|
||||
ssh -i ~/.ssh/tools.pem root@101.200.136.200
|
||||
|
||||
# 3. 创建目录和配置
|
||||
mkdir -p /opt/act_runner_<name>
|
||||
cat > /opt/act_runner_<name>/config.yaml << 'EOF'
|
||||
log:
|
||||
level: info
|
||||
runner:
|
||||
file: .runner
|
||||
capacity: 1
|
||||
timeout: 30m
|
||||
labels:
|
||||
- "<label>:host" # host 模式用系统 shell
|
||||
# 或 "<label>:docker://image" # docker 模式
|
||||
cache:
|
||||
enabled: false
|
||||
EOF
|
||||
|
||||
# 4. 注册
|
||||
cd /opt/act_runner_<name>
|
||||
act_runner register --instance https://gitea.pipexerp.com \
|
||||
--token <TOKEN> --name <NAME> --labels '<LABEL>:host' \
|
||||
--config config.yaml --no-interactive
|
||||
|
||||
# 5. 启动
|
||||
nohup act_runner daemon --config config.yaml > runner.log 2>&1 &
|
||||
echo $! > runner.pid
|
||||
```
|
||||
|
||||
### Runner 运维
|
||||
|
||||
```bash
|
||||
# 检查 runner 状态
|
||||
ssh -i ~/.ssh/tools.pem root@101.200.136.200 "ps aux | grep act_runner | grep -v grep"
|
||||
|
||||
# 查看 deploy runner 日志
|
||||
ssh -i ~/.ssh/tools.pem root@101.200.136.200 "tail -20 /opt/act_runner_deploy/runner.log"
|
||||
|
||||
# 重启 deploy runner
|
||||
ssh -i ~/.ssh/tools.pem root@101.200.136.200 "
|
||||
kill \$(cat /opt/act_runner_deploy/runner.pid) 2>/dev/null
|
||||
cd /opt/act_runner_deploy
|
||||
nohup act_runner daemon --config config.yaml > runner.log 2>&1 &
|
||||
echo \$! > runner.pid
|
||||
"
|
||||
```
|
||||
|
||||
## Workflows (coolbuy-paas)
|
||||
|
||||
| Workflow | 触发 | Runner | paths-ignore | 用途 |
|
||||
|----------|------|--------|-------------|------|
|
||||
| 🚀 deploy-staging.yml | push → main | `deploy` | md, docs, .gitea, scripts, *_test.go | 触发 Jenkins 部署到 staging |
|
||||
| 🔍 lint.yml | PR → main | `ubuntu-latest` | md, docs, .gitea, scripts | Go lint + ESLint auto-fix |
|
||||
| 🧪 unit-test.yml | PR → main | `ubuntu-latest` | md, docs, .gitea, scripts | 4 个 Go 服务单元测试 |
|
||||
| 🎭 e2e-tests.yml | schedule 12h | `ubuntu-latest` | — | Playwright E2E(仅定时) |
|
||||
| 📋 notify-aiproj.yml | PR merged | `ubuntu-latest` | — | 同步需求状态到 ai-proj |
|
||||
| 📦 build.yaml | 手动 | `ubuntu-latest` | — | Docker 构建推 Hub |
|
||||
|
||||
### Workflow 编写规范
|
||||
|
||||
```yaml
|
||||
# 1. 名称加 emoji 前缀
|
||||
name: "🚀 Deploy Staging"
|
||||
|
||||
# 2. 非代码变更加 paths-ignore
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- '*.md'
|
||||
- 'docs/**'
|
||||
- '.gitea/**'
|
||||
- 'scripts/**'
|
||||
|
||||
# 3. 加 concurrency 防重复
|
||||
concurrency:
|
||||
group: deploy-staging
|
||||
cancel-in-progress: true
|
||||
|
||||
# 4. 仅定时的 workflow 加 event 守卫
|
||||
jobs:
|
||||
e2e:
|
||||
if: github.event_name == 'schedule'
|
||||
|
||||
# 5. auto-fix 提交加 [skip ci]
|
||||
git commit -m "style: auto-fix [skip ci]"
|
||||
```
|
||||
|
||||
### Checkout 模式(容器内)
|
||||
|
||||
Gitea Actions 不支持 `actions/checkout`,用原生 git:
|
||||
|
||||
```yaml
|
||||
- name: Checkout
|
||||
env:
|
||||
TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
git config --global --add safe.directory "$(pwd)"
|
||||
git init
|
||||
git remote add origin "https://oauth2:${TOKEN}@gitea.pipexerp.com/${{ github.repository }}.git"
|
||||
git fetch origin "${{ github.event.pull_request.head.ref }}"
|
||||
git checkout -b pr-branch "origin/${{ github.event.pull_request.head.ref }}"
|
||||
git config user.name "CI Bot"
|
||||
git config user.email "ci@pipexerp.com"
|
||||
```
|
||||
|
||||
## Secrets 管理
|
||||
|
||||
### 当前 Secrets (coolbuy-paas 仓库级)
|
||||
|
||||
| Secret | 用途 |
|
||||
|--------|------|
|
||||
| `JENKINS_USER` | Jenkins API 用户名 |
|
||||
| `JENKINS_TOKEN` | Jenkins API Token |
|
||||
| `DOCKER_HUB_TOKEN` | Docker Hub 推送 |
|
||||
| `AI_PROJ_TOKEN` | ai-proj API 认证 |
|
||||
|
||||
### 添加/更新 Secret
|
||||
|
||||
```bash
|
||||
curl -s -X PUT \
|
||||
"https://gitea.pipexerp.com/api/v1/repos/pipexerp/coolbuy-paas/actions/secrets/<NAME>" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"data": "<VALUE>"}'
|
||||
```
|
||||
|
||||
## CI/CD 完整流程
|
||||
|
||||
```
|
||||
PR → main
|
||||
├── 🧪 unit-test.yml (Go 服务测试)
|
||||
├── 🔍 lint.yml (auto-fix 格式)
|
||||
└── merge 后:
|
||||
├── 📋 notify-aiproj.yml (需求状态 → testing)
|
||||
└── 🚀 deploy-staging.yml (Jenkins → staging)
|
||||
├── ≥5 commits/2h → 立即部署
|
||||
└── <5 commits → 等3分钟 debounce
|
||||
|
||||
定时:
|
||||
└── 🎭 e2e-tests.yml (每12h Playwright)
|
||||
|
||||
手动:
|
||||
└── 📦 build.yaml (Docker 构建推 Hub)
|
||||
|
||||
生产部署:
|
||||
└── ./scripts/build-and-push.sh prod --deploy (触发 Jenkins)
|
||||
```
|
||||
|
||||
## 本地 CLI 工具
|
||||
|
||||
### tea CLI (Gitea 官方命令行)
|
||||
|
||||
tea 是 Gitea 官方 CLI 客户端,已配置好认证信息。
|
||||
|
||||
```bash
|
||||
# 配置文件位置
|
||||
~/Library/Application Support/tea/config.yml
|
||||
# 或 ~/.config/tea/config.yml
|
||||
|
||||
# gitea-runs 脚本从 tea config 读取 url 和 token
|
||||
```
|
||||
|
||||
### gitea-runs (Actions 快捷命令)
|
||||
|
||||
位置: `~/.local/bin/gitea-runs`
|
||||
|
||||
自动从 git remote 检测仓库,从 tea CLI 配置读取认证信息。
|
||||
|
||||
| 命令 | 说明 |
|
||||
|------|------|
|
||||
| `gitea-runs` | 列出最近 10 条 run |
|
||||
| `gitea-runs list [N]` | 列出最近 N 条 run |
|
||||
| `gitea-runs view <run_number>` | 查看 run 详情和 jobs |
|
||||
| `gitea-runs open [run_number]` | 在浏览器打开 run 页面 |
|
||||
| `gitea-runs workflows` | 列出所有 workflow |
|
||||
| `gitea-runs dispatch <wf> [ref]` | 手动触发 workflow |
|
||||
|
||||
```bash
|
||||
# 示例
|
||||
gitea-runs # 查看最近 runs
|
||||
gitea-runs view 303 # 查看 run #303 详情
|
||||
gitea-runs dispatch deploy-staging.yml main # 手动触发部署
|
||||
gitea-runs open # 打开 Actions 页面
|
||||
```
|
||||
|
||||
**优先使用 `gitea-runs` 而非 curl API**,更简洁且自动处理认证。
|
||||
|
||||
## 常见问题
|
||||
|
||||
| 问题 | 原因 | 解决 |
|
||||
|------|------|------|
|
||||
| Run 一直 queued | Runner 被占满 | 等其他 job 完成,或加 runner |
|
||||
| deploy 被 test 阻塞 | 共用 runner | 用 `runs-on: deploy` 专属 runner |
|
||||
| Workflow 被误触发 | push 新 workflow 文件到 main | 加 `if: github.event_name == 'schedule'` 守卫 |
|
||||
| auto-fix 无限循环 | 提交触发新 run | 提交信息加 `[skip ci]` |
|
||||
| API 无法 cancel run | Gitea 1.25 限制 | 网页手动取消,或等完成后 DELETE |
|
||||
| `date -d` 报错 | 容器 date 不兼容 | 用 host 模式 runner,或兼容写法 |
|
||||
@@ -199,3 +199,50 @@ One paragraph explaining the motivation.
|
||||
↓
|
||||
tea pr merge 42
|
||||
```
|
||||
|
||||
## Finishing a Branch
|
||||
|
||||
Verify tests pass, then create PR. Use after implementation is complete.
|
||||
|
||||
**Core principle:** Verify tests → Create PR → Done.
|
||||
|
||||
### Process
|
||||
|
||||
1. **Verify Tests** — Run project's test suite before creating PR:
|
||||
```bash
|
||||
npm test / cargo test / pytest / go test ./... / mvn test
|
||||
```
|
||||
- Tests fail → Stop, show failures, fix first. Cannot proceed.
|
||||
- Tests pass → Continue to step 2.
|
||||
|
||||
2. **Create PR** — Use `/pr create` (checks for existing PR, avoids duplicates). Report PR URL.
|
||||
|
||||
3. **Cleanup Worktree** (if applicable):
|
||||
```bash
|
||||
git worktree list | grep $(git branch --show-current)
|
||||
# If in worktree, ask user to confirm removal
|
||||
git worktree remove <worktree-path>
|
||||
```
|
||||
|
||||
**Never:** Create PR with failing tests. Skip test verification. Force-push without request.
|
||||
|
||||
## Plan Execution
|
||||
|
||||
Load plan → create branch → execute tasks in batches → report for review between batches.
|
||||
|
||||
### Process
|
||||
|
||||
1. **Load Plan**: Read plan file, review critically, raise concerns before starting
|
||||
2. **Setup Branch**: Use `/pr start` or manual `git checkout -b <type>/<name> origin/main`
|
||||
3. **Execute Batch**: Default 3 tasks per batch, mark in_progress → completed
|
||||
4. **Report**: Show implementation + verification output. Say: "Ready for feedback."
|
||||
5. **Continue**: Apply feedback, execute next batch, repeat
|
||||
6. **Complete**: Use "Finishing a Branch" workflow above
|
||||
|
||||
### Stop Conditions
|
||||
|
||||
- Hit blocker (missing dependency, test fails, instruction unclear)
|
||||
- Plan has critical gaps preventing starting
|
||||
- Verification fails repeatedly
|
||||
|
||||
**Ask for clarification rather than guessing.**
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "openclaw-ops-plugin",
|
||||
"description": "Plugin for openclaw-ops",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,797 +0,0 @@
|
||||
# OpenClaw 运维技能
|
||||
|
||||
OpenClaw 容器化部署、运维监控、故障排查完整指南。
|
||||
|
||||
## 目录
|
||||
|
||||
- [服务器部署](#服务器部署)
|
||||
- [容器管理](#容器管理)
|
||||
- [性能优化](#性能优化)
|
||||
- [故障排查](#故障排查)
|
||||
- [最佳实践](#最佳实践)
|
||||
|
||||
---
|
||||
|
||||
## 服务器部署
|
||||
|
||||
### 懒猫算力仓 (lazycat)
|
||||
|
||||
**服务器信息**:
|
||||
- 主机名:haiqing.heiyu.space
|
||||
- SSH 别名:lazycat, lanmao
|
||||
- 用途:OpenClaw 算力服务
|
||||
- 系统:Debian-based Linux
|
||||
- 容器平台:lzc-docker
|
||||
|
||||
**OpenClaw 容器信息**:
|
||||
- 容器 ID:5f3bf33e090b
|
||||
- 镜像:registry.lazycat.cloud/openclaw:1.1.5
|
||||
- OpenClaw 版本:2026.2.9
|
||||
- 容器名:iamxiaoelzcappopenclaw-openclaw-1
|
||||
|
||||
**访问方式**:
|
||||
```bash
|
||||
# SSH 连接
|
||||
ssh lazycat
|
||||
|
||||
# 进入容器
|
||||
ssh lazycat "lzc-docker exec -it 5f3bf33e090b bash"
|
||||
|
||||
# 启动 OpenClaw TUI
|
||||
openclaw-tui # 使用本地快捷脚本
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 容器管理
|
||||
|
||||
### 快捷访问脚本
|
||||
|
||||
**~/bin/openclaw-tui**:
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# OpenClaw TUI 快捷访问脚本(自动启动 Gateway)
|
||||
|
||||
set -e
|
||||
|
||||
echo "🦞 连接到龙虾服务器 (懒猫)..."
|
||||
echo ""
|
||||
|
||||
# 检查并启动 Gateway
|
||||
echo "检查 OpenClaw Gateway 状态..."
|
||||
GATEWAY_STATUS=$(ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status" 2>/dev/null | grep "RPC probe" || echo "failed")
|
||||
|
||||
if echo "$GATEWAY_STATUS" | grep -q "ok"; then
|
||||
echo "✅ Gateway 已运行"
|
||||
else
|
||||
echo "🔧 启动 Gateway..."
|
||||
ssh lazycat "lzc-docker exec -d 5f3bf33e090b bash -c 'nohup openclaw gateway run > /tmp/gateway.log 2>&1 &'" 2>/dev/null
|
||||
sleep 2
|
||||
echo "✅ Gateway 已启动"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "启动 OpenClaw TUI..."
|
||||
|
||||
# SSH 到懒猫服务器,然后进入 Docker 容器并启动 OpenClaw TUI
|
||||
ssh -t lazycat "lzc-docker exec -it 5f3bf33e090b bash -c 'openclaw tui'"
|
||||
```
|
||||
|
||||
### 容器操作命令
|
||||
|
||||
```bash
|
||||
# 查看容器状态
|
||||
ssh lazycat "lzc-docker ps | grep openclaw"
|
||||
|
||||
# 查看容器日志
|
||||
ssh lazycat "lzc-docker logs -f 5f3bf33e090b --tail 100"
|
||||
|
||||
# 重启容器
|
||||
ssh lazycat "lzc-docker restart 5f3bf33e090b"
|
||||
|
||||
# 查看容器资源使用
|
||||
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
|
||||
|
||||
# 进入容器 shell
|
||||
ssh lazycat "lzc-docker exec -it 5f3bf33e090b bash"
|
||||
```
|
||||
|
||||
### Gateway 管理
|
||||
|
||||
```bash
|
||||
# 检查 Gateway 状态
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status"
|
||||
|
||||
# 启动 Gateway(前台)
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway run"
|
||||
|
||||
# 启动 Gateway(后台)
|
||||
ssh lazycat "lzc-docker exec -d 5f3bf33e090b bash -c 'nohup openclaw gateway run > /tmp/gateway.log 2>&1 &'"
|
||||
|
||||
# 停止 Gateway
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -f 'openclaw-gateway'"
|
||||
|
||||
# 查看 Gateway 日志
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b tail -f /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 性能优化
|
||||
|
||||
### 资源配置
|
||||
|
||||
**当前配置**(接近系统上限,确保充足性能):
|
||||
- 内存限制:30GB(系统 97%)
|
||||
- 内存+交换:32GB
|
||||
- CPU 限制:8.0 核心(系统 100%)
|
||||
- 进程限制:10,000 个
|
||||
|
||||
```bash
|
||||
# 查看资源限制配置
|
||||
ssh lazycat "lzc-docker inspect 5f3bf33e090b --format='
|
||||
内存限制: {{.HostConfig.Memory}} bytes
|
||||
内存+交换: {{.HostConfig.MemorySwap}} bytes
|
||||
CPU配额: {{.HostConfig.CpuQuota}}
|
||||
CPU周期: {{.HostConfig.CpuPeriod}}
|
||||
PID限制: {{.HostConfig.PidsLimit}}
|
||||
'"
|
||||
|
||||
# 查看实时资源使用
|
||||
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
|
||||
```
|
||||
|
||||
**配置说明**:
|
||||
- 懒猫算力仓的主要职责是提供 OpenClaw 服务
|
||||
- 资源限制设置为接近系统上限,确保有充足资源运行
|
||||
- 同时提供基本的失控保护机制
|
||||
|
||||
### 自动化优化措施
|
||||
|
||||
#### 1. 定期自动重启(每周日 03:00)
|
||||
|
||||
**目的**:清理累积的僵尸进程,释放资源
|
||||
|
||||
**查看状态**:
|
||||
```bash
|
||||
# 查看定时任务状态
|
||||
ssh lazycat "systemctl status openclaw-restart.timer"
|
||||
|
||||
# 查看重启日志
|
||||
ssh lazycat "tail -50 /var/log/openclaw-restart.log"
|
||||
|
||||
# 手动执行重启
|
||||
ssh lazycat "/root/restart-openclaw.sh"
|
||||
```
|
||||
|
||||
**配置文件**:
|
||||
- Service: `/etc/systemd/system/openclaw-restart.service`
|
||||
- Timer: `/etc/systemd/system/openclaw-restart.timer`
|
||||
- 脚本: `/root/restart-openclaw.sh`
|
||||
|
||||
**重启脚本** (`/root/restart-openclaw.sh`):
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# OpenClaw 容器定期重启脚本
|
||||
# 每周日凌晨3点执行
|
||||
|
||||
LOG_FILE='/var/log/openclaw-restart.log'
|
||||
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始重启 OpenClaw 容器" >> $LOG_FILE
|
||||
|
||||
# 重启容器
|
||||
/lzcsys/bin/lzc-docker restart 5f3bf33e090b >> $LOG_FILE 2>&1
|
||||
|
||||
# 等待容器启动
|
||||
sleep 10
|
||||
|
||||
# 检查健康状态
|
||||
STATUS=$(/lzcsys/bin/lzc-docker inspect -f '{{.State.Health.Status}}' 5f3bf33e090b 2>/dev/null || echo 'unknown')
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 重启完成,健康状态: $STATUS" >> $LOG_FILE
|
||||
|
||||
# 检查僵尸进程
|
||||
ZOMBIE_COUNT=$(/lzcsys/bin/lzc-docker exec 5f3bf33e090b ps aux | grep 'Z' | wc -l)
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 当前僵尸进程数: $ZOMBIE_COUNT" >> $LOG_FILE
|
||||
echo "----------------------------------------" >> $LOG_FILE
|
||||
```
|
||||
|
||||
#### 2. 僵尸进程自动监控(每小时检查)
|
||||
|
||||
**目的**:监控僵尸进程数量,超过阈值自动重启容器
|
||||
|
||||
**查看状态**:
|
||||
```bash
|
||||
# 查看监控状态
|
||||
ssh lazycat "systemctl status openclaw-zombie-monitor.timer"
|
||||
|
||||
# 查看监控日志
|
||||
ssh lazycat "tail -50 /var/log/openclaw-zombie-monitor.log"
|
||||
|
||||
# 手动检查僵尸进程
|
||||
ssh lazycat "/root/monitor-openclaw-zombies.sh"
|
||||
|
||||
# 直接查看僵尸进程数
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep 'Z' | wc -l"
|
||||
```
|
||||
|
||||
**监控参数**:
|
||||
- 检查频率:每小时
|
||||
- 触发阈值:50 个僵尸进程
|
||||
- 自动操作:重启容器
|
||||
|
||||
**监控脚本** (`/root/monitor-openclaw-zombies.sh`):
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# OpenClaw 僵尸进程监控脚本
|
||||
# 当僵尸进程超过50个时自动重启容器
|
||||
|
||||
ZOMBIE_THRESHOLD=50
|
||||
CONTAINER_ID='5f3bf33e090b'
|
||||
LOG_FILE='/var/log/openclaw-zombie-monitor.log'
|
||||
|
||||
# 检查僵尸进程数量
|
||||
ZOMBIE_COUNT=$(/lzcsys/bin/lzc-docker exec $CONTAINER_ID ps aux 2>/dev/null | grep -c 'Z' || echo '0')
|
||||
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 僵尸进程数: $ZOMBIE_COUNT" >> $LOG_FILE
|
||||
|
||||
if [ $ZOMBIE_COUNT -gt $ZOMBIE_THRESHOLD ]; then
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ⚠️ 僵尸进程超过阈值($ZOMBIE_THRESHOLD),执行自动重启" >> $LOG_FILE
|
||||
|
||||
# 重启容器
|
||||
/lzcsys/bin/lzc-docker restart $CONTAINER_ID >> $LOG_FILE 2>&1
|
||||
|
||||
# 等待容器启动
|
||||
sleep 10
|
||||
|
||||
# 再次检查
|
||||
NEW_ZOMBIE_COUNT=$(/lzcsys/bin/lzc-docker exec $CONTAINER_ID ps aux 2>/dev/null | grep -c 'Z' || echo '0')
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 重启后僵尸进程数: $NEW_ZOMBIE_COUNT" >> $LOG_FILE
|
||||
echo "----------------------------------------" >> $LOG_FILE
|
||||
fi
|
||||
```
|
||||
|
||||
#### 3. 全面健康检查
|
||||
|
||||
```bash
|
||||
# 一键健康检查脚本
|
||||
ssh lazycat "
|
||||
echo '=== 系统负载 ===' && uptime &&
|
||||
echo '' && echo '=== 僵尸进程 ===' &&
|
||||
lzc-docker exec 5f3bf33e090b ps aux | grep 'Z' | wc -l &&
|
||||
echo '' && echo '=== 容器资源 ===' &&
|
||||
lzc-docker stats --no-stream 5f3bf33e090b &&
|
||||
echo '' && echo '=== Gateway 状态 ===' &&
|
||||
lzc-docker exec 5f3bf33e090b openclaw gateway status | grep 'RPC probe' &&
|
||||
echo '' && echo '=== 容器健康 ===' &&
|
||||
lzc-docker inspect 5f3bf33e090b --format='Status: {{.State.Status}}, Health: {{.State.Health.Status}}'
|
||||
"
|
||||
|
||||
# 查看所有定时任务
|
||||
ssh lazycat "systemctl list-timers | grep openclaw"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
### Tower 反复崩溃(已修复 2026-02-16)
|
||||
|
||||
**现象**:
|
||||
- Tower 日志显示反复崩溃:`[tower] OpenClaw crashed: exit status 1`
|
||||
- Gateway 启动失败:`gateway already running (pid xxx); lock timeout`
|
||||
- 僵尸 Gateway 进程堆积,无法回收
|
||||
- 日志中出现多个僵尸进程:`[openclaw-gatewa] <defunct>`
|
||||
|
||||
**典型错误日志**:
|
||||
```
|
||||
[22:19:39] [tower] OpenClaw crashed: exit status 1
|
||||
[22:24:52] [tower] OpenClaw crashed: signal: killed
|
||||
[22:27:33] Gateway failed to start: gateway already running (pid 2005)
|
||||
[22:27:33] If the gateway is supervised, stop it with: openclaw gateway stop
|
||||
```
|
||||
|
||||
**根本原因**:
|
||||
- Tower 作为容器 PID 1 进程,不是专业的 init 进程
|
||||
- 缺少子进程回收(reaping)机制,导致僵尸进程未被清理
|
||||
- 僵尸进程占用锁文件和端口(18789),阻塞新 Gateway 启动
|
||||
- 容器 PID 1 是 `/usr/local/bin/tower`,没有僵尸进程回收能力
|
||||
|
||||
**诊断命令**:
|
||||
```bash
|
||||
# 查看 PID 1 进程
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -p 1 -o pid,ppid,cmd"
|
||||
|
||||
# 查看僵尸进程详情
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep 'defunct'"
|
||||
|
||||
# 检查端口占用
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b netstat -tlnp | grep 18789"
|
||||
|
||||
# 查看进程树
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps auxf | head -30"
|
||||
```
|
||||
|
||||
**永久解决方案(已实施)**:
|
||||
|
||||
使用 **tini** 作为容器 PID 1,自动回收僵尸进程。
|
||||
|
||||
```bash
|
||||
# 1. 在容器中安装 tini(专业 init 进程)
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b bash -c 'apt-get update -qq && apt-get install -y tini'"
|
||||
|
||||
# 2. 修改 entrypoint 使用 tini 包装 tower
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b sed -i 's|exec /usr/local/bin/tower|exec /usr/bin/tini -- /usr/local/bin/tower|g' /usr/local/bin/clawdbot-entrypoint.sh"
|
||||
|
||||
# 3. 验证修改
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b grep 'exec.*tower' /usr/local/bin/clawdbot-entrypoint.sh"
|
||||
# 应该看到: exec /usr/bin/tini -- /usr/local/bin/tower ...
|
||||
|
||||
# 4. 重启容器使修改生效
|
||||
ssh lazycat "lzc-docker restart 5f3bf33e090b"
|
||||
|
||||
# 5. 验证 tini 已成为 PID 1
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -p 1 -o pid,ppid,cmd"
|
||||
# 输出应显示: PID 1 -> /usr/bin/tini -- /usr/local/bin/tower ...
|
||||
|
||||
# 6. 检查进程树
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps auxf | head -15"
|
||||
```
|
||||
|
||||
**修复后的进程架构**:
|
||||
```
|
||||
PID 1: /usr/bin/tini (专业 init 进程,自动回收僵尸进程)
|
||||
└─ PID 58: tower
|
||||
└─ PID 64: openclaw
|
||||
└─ PID 72: openclaw-gateway
|
||||
```
|
||||
|
||||
**修复效果**:
|
||||
- ✅ Tini 作为 PID 1,自动回收所有僵尸进程
|
||||
- ✅ 僵尸进程数量从 5+ 个降至 1-2 个(健康水平)
|
||||
- ✅ Tower 稳定运行,不再反复崩溃
|
||||
- ✅ Gateway 启动正常,无锁文件冲突
|
||||
- ✅ RPC probe 持续显示 ok
|
||||
|
||||
**注意事项**:
|
||||
- ⚠️ 当前修改在运行容器内,**容器重建后需重新应用**
|
||||
- 💡 建议向镜像维护者(懒猫云)提交 PR,在 Dockerfile 中添加 tini
|
||||
- 📌 每次从镜像重新创建容器时,需要重新执行上述步骤 1-4
|
||||
|
||||
**镜像级永久修复**(建议提交给懒猫云):
|
||||
|
||||
在 OpenClaw 镜像的 Dockerfile 中添加:
|
||||
```dockerfile
|
||||
# 安装 tini
|
||||
RUN apt-get update && apt-get install -y tini && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 或使用更轻量的安装方式
|
||||
ADD https://github.com/krallin/tini/releases/download/v0.19.0/tini /usr/bin/tini
|
||||
RUN chmod +x /usr/bin/tini
|
||||
|
||||
# 在 entrypoint 脚本中使用 tini 包装(已在当前镜像的 entrypoint 中修改)
|
||||
```
|
||||
|
||||
### 僵尸进程过多
|
||||
|
||||
**现象**:
|
||||
- 僵尸进程数超过 50 个
|
||||
- Gateway 响应变慢
|
||||
- 容器内存占用升高
|
||||
|
||||
**诊断**:
|
||||
```bash
|
||||
# 查看僵尸进程详情
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep 'Z'"
|
||||
|
||||
# 统计僵尸进程数量
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z'"
|
||||
|
||||
# 查看僵尸进程父进程
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -eo pid,ppid,stat,comm | grep 'Z'"
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 方案 1:重启容器(推荐)
|
||||
ssh lazycat "lzc-docker restart 5f3bf33e090b"
|
||||
|
||||
# 方案 2:手动清理 Gateway 进程
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -9 -f 'openclaw-gateway'"
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway run &"
|
||||
|
||||
# 验证清理效果
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z'"
|
||||
```
|
||||
|
||||
### Gateway 无响应
|
||||
|
||||
**现象**:
|
||||
- `RPC probe: failed` 或超时
|
||||
- TUI 连接失败:`gateway not connected`
|
||||
- Dashboard 无法访问
|
||||
|
||||
**诊断**:
|
||||
```bash
|
||||
# 检查 Gateway 进程
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep gateway"
|
||||
|
||||
# 检查端口监听
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b netstat -tlnp | grep 18789"
|
||||
|
||||
# 查看 Gateway 日志
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b tail -100 /tmp/openclaw/openclaw-*.log"
|
||||
|
||||
# 测试本地连接
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b curl -I http://127.0.0.1:18789"
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 1. 杀死所有 Gateway 进程
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -9 -f 'openclaw-gateway'"
|
||||
|
||||
# 2. 启动新的 Gateway
|
||||
ssh lazycat "lzc-docker exec -d 5f3bf33e090b bash -c 'openclaw gateway run > /tmp/gateway.log 2>&1 &'"
|
||||
|
||||
# 3. 等待启动
|
||||
sleep 5
|
||||
|
||||
# 4. 验证状态
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status"
|
||||
```
|
||||
|
||||
### 多个 OpenClaw TUI 实例运行(已修复 2026-02-16)
|
||||
|
||||
**现象**:
|
||||
- 每次启动 OpenClaw TUI 前需要 `pkill -9 openclaw`
|
||||
- 启动失败或端口冲突
|
||||
- 多个 `openclaw-tui` 进程在后台运行
|
||||
- 容器资源占用异常高
|
||||
|
||||
**诊断**:
|
||||
```bash
|
||||
# 检查运行中的 OpenClaw 进程
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep openclaw"
|
||||
|
||||
# 通常会看到多个 openclaw-tui 实例:
|
||||
# PID 3041 - openclaw-tui (pts/0)
|
||||
# PID 6338 - openclaw-tui (pts/1)
|
||||
# PID 7223 - openclaw-tui (pts/2)
|
||||
|
||||
# 检查端口占用
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b netstat -tlnp | grep 18789"
|
||||
```
|
||||
|
||||
**根本原因**:
|
||||
- 每次运行 `openclaw tui` 都启动新进程
|
||||
- 退出 TUI 时进程没有完全清理
|
||||
- 多个实例同时运行导致资源竞争
|
||||
|
||||
**永久解决方案(已实施)**:
|
||||
|
||||
**1. 创建自动清理脚本**(容器中):
|
||||
|
||||
```bash
|
||||
# 在容器中创建 /usr/local/bin/openclaw-clean
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b bash -c \"cat > /usr/local/bin/openclaw-clean << 'EOF'
|
||||
#!/bin/bash
|
||||
# OpenClaw 清理并重启脚本
|
||||
|
||||
# 清理所有非 Tower 管理的 openclaw 进程
|
||||
echo '🧹 清理旧的 OpenClaw 进程...'
|
||||
pkill -9 -f 'openclaw-tui' || true
|
||||
pkill -9 -f 'openclaw tui' || true
|
||||
|
||||
# 等待进程完全退出
|
||||
sleep 1
|
||||
|
||||
# 检查剩余进程
|
||||
REMAINING=\\\$(ps aux | grep -E 'openclaw' | grep -v 'openclaw-gateway' | grep -v 'tower' | grep -v 'grep' | wc -l)
|
||||
if [ \\\$REMAINING -gt 0 ]; then
|
||||
echo '⚠️ 警告:还有 '\\\$REMAINING' 个 openclaw 进程'
|
||||
else
|
||||
echo '✅ 清理完成'
|
||||
fi
|
||||
|
||||
# 启动 OpenClaw TUI
|
||||
echo ''
|
||||
echo '🦞 启动 OpenClaw TUI...'
|
||||
exec openclaw tui
|
||||
EOF
|
||||
chmod +x /usr/local/bin/openclaw-clean\""
|
||||
```
|
||||
|
||||
**2. 更新本地 openclaw-tui 脚本**:
|
||||
|
||||
修改 `~/bin/openclaw-tui` 的最后一行:
|
||||
|
||||
```bash
|
||||
# 修改前
|
||||
ssh -t lazycat "lzc-docker exec -it 5f3bf33e090b bash -c 'openclaw tui'"
|
||||
|
||||
# 修改后
|
||||
ssh -t lazycat "lzc-docker exec -it 5f3bf33e090b openclaw-clean"
|
||||
```
|
||||
|
||||
**修复效果**:
|
||||
- ✅ 每次启动自动清理旧进程
|
||||
- ✅ 不再需要手动 `pkill -9 openclaw`
|
||||
- ✅ 避免多实例导致的资源浪费
|
||||
- ✅ 一条命令 `openclaw-tui` 搞定所有
|
||||
|
||||
**使用方法**:
|
||||
|
||||
```bash
|
||||
# 以前(需要手动清理)
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b bash -c 'pkill -9 openclaw && openclaw tui'"
|
||||
|
||||
# 现在(自动清理)
|
||||
openclaw-tui # 一条命令搞定!
|
||||
```
|
||||
|
||||
**手动清理**(如果需要):
|
||||
|
||||
```bash
|
||||
# 清理所有 openclaw-tui 进程
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -9 -f 'openclaw-tui'"
|
||||
|
||||
# 验证清理结果
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep openclaw | grep -v tower | grep -v openclaw-gateway"
|
||||
```
|
||||
|
||||
### 容器内存不足
|
||||
|
||||
**现象**:
|
||||
- 容器内存使用率超过 90%
|
||||
- OOM (Out of Memory) 错误
|
||||
- 进程被 killed
|
||||
|
||||
**诊断**:
|
||||
```bash
|
||||
# 检查内存使用
|
||||
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
|
||||
|
||||
# 查看内存限制
|
||||
ssh lazycat "lzc-docker inspect 5f3bf33e090b --format='{{.HostConfig.Memory}}'"
|
||||
|
||||
# 查看系统总内存
|
||||
ssh lazycat "free -h"
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
```bash
|
||||
# 调整内存限制(如果当前限制过低)
|
||||
# 注意:懒猫算力仓已设置为 30GB,一般不需要调整
|
||||
|
||||
# 如确需调整,使用以下命令
|
||||
ssh lazycat "lzc-docker update 5f3bf33e090b --memory=30g --memory-swap=32g"
|
||||
|
||||
# 重启容器使配置生效
|
||||
ssh lazycat "lzc-docker restart 5f3bf33e090b"
|
||||
```
|
||||
|
||||
### 自动重启失败
|
||||
|
||||
**现象**:
|
||||
- systemd timer 未触发
|
||||
- 重启脚本执行失败
|
||||
- 日志显示 `lzc-docker: command not found`
|
||||
|
||||
**诊断**:
|
||||
```bash
|
||||
# 检查 timer 状态
|
||||
ssh lazycat "systemctl status openclaw-restart.timer"
|
||||
|
||||
# 检查 service 状态
|
||||
ssh lazycat "systemctl status openclaw-restart.service"
|
||||
|
||||
# 查看 service 日志
|
||||
ssh lazycat "journalctl -u openclaw-restart.service -n 50"
|
||||
|
||||
# 查看脚本日志
|
||||
ssh lazycat "tail -50 /var/log/openclaw-restart.log"
|
||||
|
||||
# 手动测试脚本
|
||||
ssh lazycat "bash -x /root/restart-openclaw.sh"
|
||||
```
|
||||
|
||||
**解决方案**:
|
||||
|
||||
问题通常是脚本中 `lzc-docker` 命令找不到(PATH 问题)。
|
||||
|
||||
```bash
|
||||
# 确认 lzc-docker 路径
|
||||
ssh lazycat "which lzc-docker"
|
||||
# 输出: /lzcsys/bin/lzc-docker
|
||||
|
||||
# 确保脚本使用完整路径
|
||||
ssh lazycat "grep 'lzc-docker' /root/restart-openclaw.sh"
|
||||
# 应该看到: /lzcsys/bin/lzc-docker
|
||||
|
||||
# 如果使用的是相对路径,需要修改
|
||||
ssh lazycat "sed -i 's|lzc-docker|/lzcsys/bin/lzc-docker|g' /root/restart-openclaw.sh"
|
||||
ssh lazycat "sed -i 's|lzc-docker|/lzcsys/bin/lzc-docker|g' /root/monitor-openclaw-zombies.sh"
|
||||
|
||||
# 重新加载 systemd 配置
|
||||
ssh lazycat "systemctl daemon-reload"
|
||||
|
||||
# 测试执行
|
||||
ssh lazycat "/root/restart-openclaw.sh"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 1. 定期健康检查
|
||||
|
||||
建议每天执行一次全面健康检查:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# OpenClaw 健康检查脚本
|
||||
|
||||
echo "🔍 OpenClaw 健康检查 - $(date)"
|
||||
echo "================================"
|
||||
|
||||
# 容器状态
|
||||
echo -e "\n📦 容器状态:"
|
||||
ssh lazycat "lzc-docker ps --filter id=5f3bf33e090b --format 'Status: {{.Status}}'"
|
||||
|
||||
# PID 1 进程
|
||||
echo -e "\n🏗️ PID 1 进程:"
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -p 1 -o pid,ppid,cmd"
|
||||
|
||||
# 僵尸进程数
|
||||
echo -e "\n👻 僵尸进程:"
|
||||
ZOMBIE_COUNT=$(ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z'")
|
||||
echo "僵尸进程数: $ZOMBIE_COUNT"
|
||||
if [ $ZOMBIE_COUNT -gt 10 ]; then
|
||||
echo "⚠️ 警告:僵尸进程较多,建议重启容器"
|
||||
fi
|
||||
|
||||
# 资源使用
|
||||
echo -e "\n💾 资源使用:"
|
||||
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
|
||||
|
||||
# Gateway 状态
|
||||
echo -e "\n🔌 Gateway 状态:"
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status | grep 'RPC probe'"
|
||||
|
||||
# 系统负载
|
||||
echo -e "\n📊 系统负载:"
|
||||
ssh lazycat "uptime"
|
||||
|
||||
echo -e "\n================================"
|
||||
echo "✅ 健康检查完成"
|
||||
```
|
||||
|
||||
### 2. 日志管理
|
||||
|
||||
```bash
|
||||
# 查看最近的错误日志
|
||||
ssh lazycat "lzc-docker logs 5f3bf33e090b --since 1h 2>&1 | grep -i error"
|
||||
|
||||
# 查看 Tower 崩溃日志
|
||||
ssh lazycat "lzc-docker logs 5f3bf33e090b 2>&1 | grep -i 'crashed\|failed'"
|
||||
|
||||
# 查看 OpenClaw 应用日志
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b tail -100 /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log"
|
||||
|
||||
# 清理旧日志(保留最近7天)
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b find /tmp/openclaw -name '*.log' -mtime +7 -delete"
|
||||
```
|
||||
|
||||
### 3. 备份与恢复
|
||||
|
||||
```bash
|
||||
# 备份 OpenClaw 配置
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b tar czf /tmp/openclaw-config-backup-$(date +%Y%m%d).tar.gz -C /home/node/.openclaw ."
|
||||
|
||||
# 下载备份到本地
|
||||
scp lazycat:/tmp/openclaw-config-backup-*.tar.gz ~/backups/
|
||||
|
||||
# 恢复配置
|
||||
scp ~/backups/openclaw-config-backup-*.tar.gz lazycat:/tmp/
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b tar xzf /tmp/openclaw-config-backup-*.tar.gz -C /home/node/.openclaw"
|
||||
ssh lazycat "lzc-docker restart 5f3bf33e090b"
|
||||
```
|
||||
|
||||
### 4. 监控告警
|
||||
|
||||
建议设置以下监控指标:
|
||||
|
||||
- **僵尸进程数** > 50:触发告警,自动重启(已实现)
|
||||
- **内存使用率** > 90%:触发告警
|
||||
- **Gateway 离线时间** > 5分钟:触发告警
|
||||
- **容器重启次数** > 3次/天:触发告警
|
||||
|
||||
### 5. 容器重建后的恢复清单
|
||||
|
||||
如果容器被重新创建(从镜像),需要重新应用以下修复:
|
||||
|
||||
```bash
|
||||
# 1. 安装 tini
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b bash -c 'apt-get update -qq && apt-get install -y tini'"
|
||||
|
||||
# 2. 修改 entrypoint
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b sed -i 's|exec /usr/local/bin/tower|exec /usr/bin/tini -- /usr/local/bin/tower|g' /usr/local/bin/clawdbot-entrypoint.sh"
|
||||
|
||||
# 3. 重启容器
|
||||
ssh lazycat "lzc-docker restart 5f3bf33e090b"
|
||||
|
||||
# 4. 验证
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps -p 1 -o cmd | grep tini"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 附录
|
||||
|
||||
### 相关文档
|
||||
|
||||
- OpenClaw 官方文档:https://docs.openclaw.ai/
|
||||
- 故障排查指南:https://docs.openclaw.ai/troubleshooting
|
||||
- Tini 项目:https://github.com/krallin/tini
|
||||
|
||||
### 联系信息
|
||||
|
||||
- 懒猫云支持:support@lazycat.cloud
|
||||
- OpenClaw 社区:https://community.openclaw.ai/
|
||||
|
||||
### 版本历史
|
||||
|
||||
- 2026-02-16:
|
||||
- 创建文档,记录 Tower 崩溃修复经验(使用 tini)
|
||||
- 添加多 TUI 实例问题和 openclaw-clean 解决方案
|
||||
- 2026-02-15:实施僵尸进程监控和自动重启
|
||||
- 2026-02-14:调整容器资源限制为接近系统上限
|
||||
|
||||
---
|
||||
|
||||
## 快速参考
|
||||
|
||||
### 常用命令速查
|
||||
|
||||
```bash
|
||||
# 连接 OpenClaw TUI
|
||||
openclaw-tui
|
||||
|
||||
# 查看容器状态
|
||||
ssh lazycat "lzc-docker ps | grep openclaw"
|
||||
|
||||
# 重启容器
|
||||
ssh lazycat "lzc-docker restart 5f3bf33e090b"
|
||||
|
||||
# 查看僵尸进程数
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z'"
|
||||
|
||||
# 检查 Gateway 状态
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw gateway status | grep 'RPC probe'"
|
||||
|
||||
# 查看资源使用
|
||||
ssh lazycat "lzc-docker stats --no-stream 5f3bf33e090b"
|
||||
|
||||
# 查看定时任务
|
||||
ssh lazycat "systemctl list-timers | grep openclaw"
|
||||
|
||||
# 清理多余的 OpenClaw TUI 进程
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b pkill -9 -f 'openclaw-tui'"
|
||||
|
||||
# 启动 OpenClaw(自动清理旧进程)
|
||||
ssh lazycat "lzc-docker exec 5f3bf33e090b openclaw-clean"
|
||||
|
||||
# 全面健康检查
|
||||
ssh lazycat "echo '=== 容器 ===' && lzc-docker ps | grep openclaw && echo '' && echo '=== 僵尸进程 ===' && lzc-docker exec 5f3bf33e090b ps aux | grep -c 'Z' && echo '' && echo '=== Gateway ===' && lzc-docker exec 5f3bf33e090b openclaw gateway status | grep 'RPC probe'"
|
||||
```
|
||||
|
||||
### 故障处理速查
|
||||
|
||||
| 问题 | 快速解决 |
|
||||
|------|----------|
|
||||
| Tower 反复崩溃 | 参考"Tower 反复崩溃"章节,安装 tini |
|
||||
| 多个 TUI 实例 | 使用 `openclaw-tui`(自动清理)或手动 `pkill -9 -f openclaw-tui` |
|
||||
| Gateway 无响应 | `ssh lazycat "lzc-docker restart 5f3bf33e090b"` |
|
||||
| 僵尸进程过多 | `ssh lazycat "lzc-docker restart 5f3bf33e090b"` |
|
||||
| 内存不足 | 检查资源限制,重启容器 |
|
||||
| 自动重启失败 | 检查脚本是否使用完整路径 `/lzcsys/bin/lzc-docker` |
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "openclaw-plugin",
|
||||
"description": "OpenClaw (龙虾) - Remote AI compute orchestration system. Dispatches requirements to Claude Code instances on remote machines, monitors execution, and aggregates results.",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,342 +0,0 @@
|
||||
---
|
||||
name: openclaw
|
||||
description: OpenClaw (龙虾) - Remote AI compute orchestration system. Dispatches requirements to Claude Code instances on remote machines, monitors execution, and aggregates results.
|
||||
---
|
||||
|
||||
# OpenClaw - Remote AI Compute Orchestration
|
||||
|
||||
OpenClaw (龙虾) 是一个分布式 AI 算力调度系统,用于将需求/任务分发到不同机器上的 Claude Code 实例执行。
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 1. Ticket (工单)
|
||||
每个需求 (Requirement) 或任务 (Task) 都是一个 Ticket,包含:
|
||||
- **ID**: REQ-YYYYMMDD-XXXX 或 Task ID
|
||||
- **Description**: 任务描述
|
||||
- **Context**: 项目路径、技术栈、依赖
|
||||
- **Priority**: 优先级 (high/medium/low)
|
||||
- **Target**: 目标计算节点
|
||||
|
||||
### 2. Compute Node (算力节点)
|
||||
运行 Claude Code 的开发机器:
|
||||
- **Melbourne** (coolbuy-dev): 主开发机,全栈开发
|
||||
- **Shanghai** (dev-box): 测试环境
|
||||
- **Beijing** (lazycat): OpenClaw 本身所在的容器
|
||||
|
||||
### 3. Dispatcher (调度器)
|
||||
OpenClaw 核心组件,负责:
|
||||
- 接收 Ticket
|
||||
- 选择合适的 Compute Node
|
||||
- 生成 Claude Code 命令
|
||||
- 通过 SSH 执行
|
||||
- 监控进度
|
||||
- 汇总结果
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 基本调用
|
||||
|
||||
```bash
|
||||
# 方式 1: 通过需求 ID
|
||||
/openclaw dispatch REQ-20260216-0001
|
||||
|
||||
# 方式 2: 直接指定任务
|
||||
/openclaw run "实现用户批量导入功能" --node melbourne --project new-ai-proj
|
||||
|
||||
# 方式 3: 使用 Swarm 模式
|
||||
/openclaw swarm REQ-20260216-0001 --node melbourne
|
||||
```
|
||||
|
||||
### 指定计算节点
|
||||
|
||||
```bash
|
||||
# 自动选择 (根据负载和项目位置)
|
||||
/openclaw dispatch REQ-20260216-0001 --auto
|
||||
|
||||
# 指定节点
|
||||
/openclaw dispatch REQ-20260216-0001 --node melbourne
|
||||
|
||||
# 并行执行 (多个节点)
|
||||
/openclaw dispatch REQ-20260216-0001 --nodes melbourne,shanghai --parallel
|
||||
```
|
||||
|
||||
### 监控执行状态
|
||||
|
||||
```bash
|
||||
# 查看所有运行中的任务
|
||||
/openclaw status
|
||||
|
||||
# 查看特定任务的日志
|
||||
/openclaw logs REQ-20260216-0001
|
||||
|
||||
# 实时追踪任务进度
|
||||
/openclaw tail REQ-20260216-0001
|
||||
```
|
||||
|
||||
## 工作流程
|
||||
|
||||
### 完整示例: 从 Feishu 到执行
|
||||
|
||||
**步骤 1: 用户在飞书发起请求**
|
||||
```
|
||||
@龙虾 执行 REQ-20260216-0001
|
||||
```
|
||||
|
||||
**步骤 2: Feishu Bot 解析命令**
|
||||
- 提取需求 ID: REQ-20260216-0001
|
||||
- 调用 OpenClaw skill
|
||||
|
||||
**步骤 3: OpenClaw 查询需求详情**
|
||||
```bash
|
||||
# 使用 ai-proj-prod MCP 获取需求信息
|
||||
mcp__ai-proj-prod__find_requirement(displayId="REQ-20260216-0001")
|
||||
```
|
||||
|
||||
**步骤 4: OpenClaw 生成执行计划**
|
||||
```json
|
||||
{
|
||||
"ticket_id": "REQ-20260216-0001",
|
||||
"title": "AI Ticket 演示: 验证算力调度系统",
|
||||
"type": "swarm",
|
||||
"target_node": "melbourne",
|
||||
"command": "/swarm start '实现 AI Ticket 从创建到算力调度的完整流程'",
|
||||
"context": {
|
||||
"project": "/Users/coolbuy-dev/coding/new-ai-proj",
|
||||
"requirement_id": "REQ-20260216-0001",
|
||||
"priority": "high"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**步骤 5: SSH 执行命令**
|
||||
```bash
|
||||
ssh coolbuy-dev@melbourne \
|
||||
"cd /Users/coolbuy-dev/coding/new-ai-proj && \
|
||||
/opt/homebrew/bin/claude --dangerously-skip-permissions \
|
||||
-p '/swarm start 实现 AI Ticket 从创建到算力调度的完整流程 \
|
||||
--context requirement_id=REQ-20260216-0001'"
|
||||
```
|
||||
|
||||
**步骤 6: Claude Code 执行 Swarm 工作流**
|
||||
- Architect Agent: 分析需求,设计方案
|
||||
- Coder Agent: 实现代码
|
||||
- Tester Agent: 编写和运行测试
|
||||
- Reviewer Agent: 代码审查
|
||||
- Deployer Agent: 部署到环境
|
||||
|
||||
**步骤 7: OpenClaw 监控和汇总**
|
||||
- 实时获取执行日志
|
||||
- 解析 Agent 切换和进度
|
||||
- 检测完成或失败
|
||||
|
||||
**步骤 8: 报告结果**
|
||||
```
|
||||
【执行完成】REQ-20260216-0001
|
||||
✅ 状态: 成功
|
||||
⏱️ 耗时: 25 分钟
|
||||
📝 修改: 12 个文件
|
||||
✅ 测试: 32 个用例全部通过
|
||||
🚀 部署: staging 环境已更新
|
||||
|
||||
详情: https://ai-proj.pipexerp.com/requirements/REQ-20260216-0001
|
||||
```
|
||||
|
||||
## 配置文件
|
||||
|
||||
### openclaw.yaml
|
||||
|
||||
在 `~/.claude/openclaw/config.yaml` 配置节点信息:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
melbourne:
|
||||
host: coolbuy-dev-macbook.local
|
||||
user: coolbuy-dev
|
||||
ssh_key: ~/.ssh/id_rsa
|
||||
claude_path: /opt/homebrew/bin/claude
|
||||
working_dirs:
|
||||
- /Users/coolbuy-dev/coding/new-ai-proj
|
||||
- /Users/coolbuy-dev/coding/coolbuy-paas
|
||||
capabilities:
|
||||
- go
|
||||
- vue
|
||||
- react
|
||||
- ios
|
||||
- android
|
||||
max_concurrent: 3
|
||||
|
||||
shanghai:
|
||||
host: dev-box.pipexerp.com
|
||||
user: devops
|
||||
ssh_key: ~/.ssh/id_rsa_ops
|
||||
claude_path: /usr/local/bin/claude
|
||||
working_dirs:
|
||||
- /home/devops/projects
|
||||
capabilities:
|
||||
- testing
|
||||
- deployment
|
||||
max_concurrent: 2
|
||||
|
||||
routing_rules:
|
||||
# 根据项目路径自动选择节点
|
||||
- pattern: "*/new-ai-proj/*"
|
||||
node: melbourne
|
||||
|
||||
- pattern: "*/coolbuy-*/*"
|
||||
node: melbourne
|
||||
|
||||
# 根据需求类别路由
|
||||
- category: testing
|
||||
node: shanghai
|
||||
|
||||
- category: feature
|
||||
node: melbourne
|
||||
priority: prefer # 非强制
|
||||
|
||||
# 默认节点
|
||||
default: melbourne
|
||||
|
||||
monitoring:
|
||||
progress_interval: 30s # 每 30 秒检查一次进度
|
||||
timeout: 2h # 2 小时超时
|
||||
feishu_notifications: true
|
||||
feishu_webhook: ${FEISHU_OPENCLAW_WEBHOOK}
|
||||
```
|
||||
|
||||
## 高级功能
|
||||
|
||||
### 1. 负载均衡
|
||||
|
||||
OpenClaw 自动根据节点负载分配任务:
|
||||
|
||||
```bash
|
||||
# 自动选择最空闲的节点
|
||||
/openclaw dispatch REQ-20260216-0001 --load-balance
|
||||
```
|
||||
|
||||
### 2. 任务队列
|
||||
|
||||
当节点繁忙时,任务进入队列:
|
||||
|
||||
```bash
|
||||
# 查看队列
|
||||
/openclaw queue
|
||||
|
||||
# 输出:
|
||||
# 队列中的任务:
|
||||
# 1. [melbourne] REQ-20260216-0002 - 等待中 (前面 1 个任务)
|
||||
# 2. [shanghai] Task-1234 - 等待中 (前面 0 个任务)
|
||||
```
|
||||
|
||||
### 3. 结果缓存
|
||||
|
||||
已执行过的相同任务可以复用结果:
|
||||
|
||||
```bash
|
||||
/openclaw dispatch REQ-20260216-0001 --use-cache
|
||||
```
|
||||
|
||||
### 4. 故障恢复
|
||||
|
||||
任务失败时自动重试或切换节点:
|
||||
|
||||
```yaml
|
||||
retry_policy:
|
||||
max_attempts: 3
|
||||
backoff: exponential # 1min, 2min, 4min
|
||||
fallback_node: shanghai # 失败后切换到备用节点
|
||||
```
|
||||
|
||||
## 与其他 Skills 集成
|
||||
|
||||
### 与 agent-swarm 集成
|
||||
```bash
|
||||
# OpenClaw 调度 Swarm 工作流
|
||||
/openclaw swarm REQ-20260216-0001 --node melbourne
|
||||
```
|
||||
|
||||
### 与 ai-proj 集成
|
||||
```bash
|
||||
# 自动更新需求状态
|
||||
# pending → in_progress → testing → completed
|
||||
/openclaw dispatch REQ-20260216-0001 --sync-status
|
||||
```
|
||||
|
||||
### 与 feishu 集成
|
||||
```bash
|
||||
# 飞书群接收进度通知
|
||||
# "【进行中】REQ-20260216-0001 - Coder Agent 正在实现后端 API (35%)"
|
||||
```
|
||||
|
||||
### 与 ops-tools 集成
|
||||
```bash
|
||||
# 部署到服务器
|
||||
/openclaw dispatch REQ-20260216-0001 --deploy staging
|
||||
```
|
||||
|
||||
## 命令速查
|
||||
|
||||
| 命令 | 功能 |
|
||||
|------|------|
|
||||
| `/openclaw dispatch <req-id>` | 调度需求到节点执行 |
|
||||
| `/openclaw run "<task>"` | 直接执行任务 |
|
||||
| `/openclaw swarm <req-id>` | 使用 Swarm 模式执行 |
|
||||
| `/openclaw status` | 查看所有任务状态 |
|
||||
| `/openclaw logs <req-id>` | 查看任务日志 |
|
||||
| `/openclaw tail <req-id>` | 实时追踪任务 |
|
||||
| `/openclaw queue` | 查看任务队列 |
|
||||
| `/openclaw nodes` | 列出所有计算节点 |
|
||||
| `/openclaw cancel <req-id>` | 取消任务 |
|
||||
|
||||
## 故障排查
|
||||
|
||||
| 问题 | 原因 | 解决方案 |
|
||||
|------|------|----------|
|
||||
| SSH 连接失败 | 网络或认证问题 | 检查 `~/.ssh/config` 和密钥权限 |
|
||||
| Claude 命令未找到 | Claude 未安装或路径错误 | 更新 `openclaw.yaml` 中的 `claude_path` |
|
||||
| 任务卡住不动 | 超时或节点挂起 | 使用 `/openclaw cancel` 取消并重试 |
|
||||
| Feishu 通知失败 | Webhook 配置错误 | 检查 `FEISHU_OPENCLAW_WEBHOOK` 环境变量 |
|
||||
|
||||
## 安全考虑
|
||||
|
||||
1. **SSH 密钥管理**: 使用专用密钥,定期轮换
|
||||
2. **命令注入防护**: 所有参数都经过严格转义
|
||||
3. **权限控制**: 限制 Claude Code 的 `--dangerously-skip-permissions` 使用
|
||||
4. **日志审计**: 所有命令执行都记录在 `~/.claude/openclaw/audit.log`
|
||||
|
||||
## 实际应用场景
|
||||
|
||||
### 场景 1: 多项目并行开发
|
||||
```bash
|
||||
# 同时在不同机器上开发不同项目
|
||||
/openclaw dispatch REQ-001 --node melbourne --project new-ai-proj &
|
||||
/openclaw dispatch REQ-002 --node shanghai --project coolbuy-paas &
|
||||
```
|
||||
|
||||
### 场景 2: 测试环境验证
|
||||
```bash
|
||||
# 开发在 Melbourne,测试在 Shanghai
|
||||
/openclaw dispatch REQ-003 --node melbourne # 开发
|
||||
sleep 1h # 等待开发完成
|
||||
/openclaw dispatch REQ-003 --node shanghai --verify # 测试验证
|
||||
```
|
||||
|
||||
### 场景 3: 紧急 Bug 修复
|
||||
```bash
|
||||
# 高优先级任务插队执行
|
||||
/openclaw dispatch BUG-001 --priority urgent --node melbourne
|
||||
```
|
||||
|
||||
## 未来扩展
|
||||
|
||||
- [ ] Web 控制面板: 可视化任务状态和节点负载
|
||||
- [ ] 分布式追踪: Jaeger/OpenTelemetry 集成
|
||||
- [ ] 成本统计: 记录每个任务的 token 使用量和费用
|
||||
- [ ] 智能调度: 基于历史数据预测任务执行时间
|
||||
- [ ] 多云支持: 支持 AWS/Azure/GCP 上的计算节点
|
||||
|
||||
---
|
||||
|
||||
**开发者**: AI 项目管理助手
|
||||
**版本**: 1.0.0
|
||||
**最后更新**: 2026-02-16
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "ops-servers-plugin",
|
||||
"description": "Plugin for ops-servers",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
---
|
||||
name: ops-servers
|
||||
description: 企业服务器管理。用于云服务器分组管理、系统监控、备份管理、故障排查。当用户提到云服务器、生产环境、腾讯云、阿里云相关任务时自动激活。
|
||||
---
|
||||
|
||||
# 企业服务器管理 Skill
|
||||
|
||||
> 家庭网络设备请使用 `ops-home` Skill
|
||||
|
||||
---
|
||||
|
||||
## 服务器清单
|
||||
|
||||
| 别名 | IP | 用户 | SSH 密钥 | 用途 | 配置 | ISP | 账号 |
|
||||
|------|-----|------|----------|------|------|-----|------|
|
||||
| prod-pipexerp | 192.144.137.14 | ubuntu | ~/.ssh/officialWebsite.pem | pipexerp 官网 | 2核2G 40G SSD | 腾讯云 | 北京对丝 |
|
||||
| prod-metaBI | 192.144.174.87 | ubuntu | ~/.ssh/prod_meta.pem | Metabase BI 分析 | - | 腾讯云 | 北京欢乐宿 |
|
||||
| moltbot | 124.223.196.74 | root | ~/.ssh/moltbot | Moltbot 服务 | - | 腾讯云 | - |
|
||||
| lazycat | 100.115.52.119 (haiqing.heiyu.space) | root | 密码认证 (zhiyun2026) | AI/计算节点 | - | - | - |
|
||||
|
||||
### SSH 快捷连接
|
||||
|
||||
```bash
|
||||
# pipexerp 官网服务器
|
||||
ssh prod-pipexerp
|
||||
|
||||
# Metabase BI 分析服务器
|
||||
ssh prod-metaBI
|
||||
|
||||
# Moltbot 服务器
|
||||
ssh moltbot
|
||||
|
||||
# Lazycat AI 计算节点(密码:zhiyun2026)
|
||||
ssh root@haiqing.heiyu.space
|
||||
# 或使用 IP
|
||||
ssh root@100.115.52.119
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 服务器分组架构
|
||||
|
||||
采用 **环境 + 服务** 混合分组模式:
|
||||
|
||||
### 按环境分组
|
||||
|
||||
| 环境 | 前缀 | 用途 |
|
||||
|------|------|------|
|
||||
| prod | prod- | 生产环境 |
|
||||
| staging | stg- | 预发布环境 |
|
||||
| test | test- | 测试环境 |
|
||||
| dev | dev- | 开发环境 |
|
||||
|
||||
### 按服务分组
|
||||
|
||||
| 服务组 | 包含服务 | 说明 |
|
||||
|--------|----------|------|
|
||||
| web | Nginx, 前端静态资源 | 负载均衡、静态资源 |
|
||||
| api | Go/Node 后端服务 | 业务 API |
|
||||
| db | MySQL, PostgreSQL | 数据库 |
|
||||
| cache | Redis | 缓存服务 |
|
||||
|
||||
---
|
||||
|
||||
## 常用运维命令
|
||||
|
||||
### 系统状态检查
|
||||
|
||||
```bash
|
||||
# 一键查看系统概况
|
||||
ssh prod-pipexerp "echo '=== 负载 ===' && uptime && echo && echo '=== 内存 ===' && free -h && echo && echo '=== 磁盘 ===' && df -h"
|
||||
|
||||
# 查看 CPU 使用最高的进程
|
||||
ssh prod-pipexerp "ps aux --sort=-%cpu | head -10"
|
||||
|
||||
# 查看内存使用最高的进程
|
||||
ssh prod-pipexerp "ps aux --sort=-%mem | head -10"
|
||||
```
|
||||
|
||||
### Docker 管理
|
||||
|
||||
```bash
|
||||
# 查看运行中的容器
|
||||
ssh prod-pipexerp "docker ps"
|
||||
|
||||
# 查看所有容器
|
||||
ssh prod-pipexerp "docker ps -a"
|
||||
|
||||
# 查看容器日志
|
||||
ssh prod-pipexerp "docker logs -f <container_name> --tail 100"
|
||||
|
||||
# 重启容器
|
||||
ssh prod-pipexerp "docker restart <container_name>"
|
||||
|
||||
# 清理未使用的资源
|
||||
ssh prod-pipexerp "docker system prune -af"
|
||||
```
|
||||
|
||||
### 网络检查
|
||||
|
||||
```bash
|
||||
# 查看端口监听
|
||||
ssh prod-pipexerp "sudo netstat -tlnp"
|
||||
|
||||
# 检查防火墙状态
|
||||
ssh prod-pipexerp "sudo ufw status"
|
||||
|
||||
# 测试端口连通性
|
||||
nc -zv 192.144.137.14 80
|
||||
nc -zv 192.144.137.14 443
|
||||
```
|
||||
|
||||
### 日志查看
|
||||
|
||||
```bash
|
||||
# Nginx 错误日志
|
||||
ssh prod-pipexerp "sudo tail -f /var/log/nginx/error.log"
|
||||
|
||||
# Nginx 访问日志
|
||||
ssh prod-pipexerp "sudo tail -f /var/log/nginx/access.log"
|
||||
|
||||
# 系统日志
|
||||
ssh prod-pipexerp "sudo tail -f /var/log/syslog"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 批量操作
|
||||
|
||||
### 对多台服务器执行命令
|
||||
|
||||
```bash
|
||||
# 定义服务器列表
|
||||
SERVERS="prod-pipexerp"
|
||||
|
||||
# 批量检查状态
|
||||
for host in $SERVERS; do
|
||||
echo "=== $host ==="
|
||||
ssh $host "uptime && free -h | head -2 && df -h / | tail -1"
|
||||
done
|
||||
```
|
||||
|
||||
### 健康检查脚本
|
||||
|
||||
```bash
|
||||
# 检查所有服务器
|
||||
for host in prod-pipexerp; do
|
||||
echo "=== $host ==="
|
||||
ssh $host "
|
||||
echo '--- 负载 ---' && uptime
|
||||
echo '--- 内存 ---' && free -h | head -2
|
||||
echo '--- 磁盘 ---' && df -h / | tail -1
|
||||
echo '--- Docker ---' && docker ps --format 'table {{.Names}}\t{{.Status}}' 2>/dev/null || echo 'N/A'
|
||||
"
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 备份管理
|
||||
|
||||
### 备份策略
|
||||
|
||||
| 备份类型 | 频率 | 保留时间 | 存储位置 |
|
||||
|----------|------|----------|----------|
|
||||
| 数据库全量 | 每日 02:00 | 7 天 | /backup/mysql/ |
|
||||
| 配置文件 | 每日 03:00 | 30 天 | /backup/configs/ |
|
||||
| 上传文件 | 每日 04:00 | 30 天 | /backup/uploads/ |
|
||||
|
||||
### 手动备份
|
||||
|
||||
```bash
|
||||
# 备份 Nginx 配置
|
||||
ssh prod-pipexerp "sudo tar -czf /tmp/nginx-\$(date +%Y%m%d).tar.gz /etc/nginx/"
|
||||
|
||||
# 下载备份到本地
|
||||
scp prod-pipexerp:/tmp/nginx-*.tar.gz ./backups/
|
||||
```
|
||||
|
||||
### 备份清理
|
||||
|
||||
```bash
|
||||
# 清理 7 天前的备份
|
||||
ssh prod-pipexerp "sudo find /backup/ -name '*.tar.gz' -mtime +7 -delete"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **服务无响应**
|
||||
```bash
|
||||
ssh prod-pipexerp "sudo systemctl status nginx"
|
||||
ssh prod-pipexerp "sudo journalctl -u nginx --since '10 minutes ago'"
|
||||
```
|
||||
|
||||
2. **磁盘空间不足**
|
||||
```bash
|
||||
ssh prod-pipexerp "df -h && sudo du -sh /* 2>/dev/null | sort -h | tail -10"
|
||||
# 清理 Docker
|
||||
ssh prod-pipexerp "docker system prune -af"
|
||||
# 清理日志
|
||||
ssh prod-pipexerp "sudo journalctl --vacuum-size=500M"
|
||||
```
|
||||
|
||||
3. **内存不足**
|
||||
```bash
|
||||
ssh prod-pipexerp "free -h && ps aux --sort=-%mem | head -10"
|
||||
```
|
||||
|
||||
4. **网站无法访问**
|
||||
```bash
|
||||
# 检查 Nginx
|
||||
ssh prod-pipexerp "sudo systemctl status nginx"
|
||||
# 检查端口
|
||||
ssh prod-pipexerp "sudo netstat -tlnp | grep ':80\|:443'"
|
||||
# 测试本地访问
|
||||
ssh prod-pipexerp "curl -I http://localhost"
|
||||
```
|
||||
|
||||
5. **SSL 证书问题**
|
||||
```bash
|
||||
# 检查证书到期时间
|
||||
ssh prod-pipexerp "sudo openssl x509 -in /etc/nginx/ssl/cert.pem -noout -dates"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 账号管理
|
||||
|
||||
### 系统用户
|
||||
|
||||
| 用户名 | 用途 | 权限 |
|
||||
|--------|------|------|
|
||||
| ubuntu | 默认管理用户 | sudo |
|
||||
| deploy | 部署用户 | 部署相关 |
|
||||
|
||||
### 创建部署用户
|
||||
|
||||
```bash
|
||||
# 创建用户
|
||||
ssh prod-pipexerp "sudo useradd -m -s /bin/bash deploy"
|
||||
|
||||
# 配置 SSH 密钥
|
||||
ssh prod-pipexerp "sudo mkdir -p /home/deploy/.ssh && sudo chmod 700 /home/deploy/.ssh"
|
||||
ssh prod-pipexerp "sudo cp ~/.ssh/authorized_keys /home/deploy/.ssh/ && sudo chown -R deploy:deploy /home/deploy/.ssh"
|
||||
|
||||
# 配置 sudo 权限(无密码 docker 和 systemctl)
|
||||
ssh prod-pipexerp "echo 'deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart *, /usr/bin/docker *' | sudo tee /etc/sudoers.d/deploy"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 安全注意事项
|
||||
|
||||
- SSH 密钥文件权限必须是 600: `chmod 600 ~/.ssh/*.pem`
|
||||
- 使用 `sudo` 执行需要 root 权限的命令
|
||||
- 敏感操作前先确认服务器和目标
|
||||
- 生产环境操作需要二次确认
|
||||
- 定期更新系统和软件包
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "ops-tools-plugin",
|
||||
"description": "Plugin for ops-tools",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,246 +0,0 @@
|
||||
# AI-Proj 部署指南
|
||||
|
||||
**创建时间**: 2026-01-29 11:50:00 CST
|
||||
**父技能**: ops-tools
|
||||
|
||||
## 环境概览
|
||||
|
||||
| 环境 | 服务器 | 域名 | 镜像标签 |
|
||||
|------|--------|------|----------|
|
||||
| 生产 | tools_ai_proj (152.136.104.251) | https://ai.pipexerp.com | `latest` |
|
||||
| 测试 | singapore (43.134.28.147) | http://staging.ai.pipexerp.com | `test` |
|
||||
|
||||
## 镜像信息
|
||||
|
||||
| 服务 | 镜像 |
|
||||
|------|------|
|
||||
| 后端 | `saltthing123/ai-proj-backend` |
|
||||
| 前端 | `saltthing123/ai-proj-frontend` |
|
||||
|
||||
## 标准部署流程
|
||||
|
||||
### 部署到测试环境
|
||||
|
||||
```bash
|
||||
cd /path/to/new-ai-proj
|
||||
|
||||
# 构建后端 test 镜像
|
||||
docker buildx build --platform linux/amd64 -f backend/Dockerfile --target production \
|
||||
-t saltthing123/ai-proj-backend:test --push backend/
|
||||
|
||||
# 构建前端 test 镜像
|
||||
docker buildx build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
|
||||
--build-arg REACT_APP_API_URL=https://staging.ai.pipexerp.com/api/v1 \
|
||||
--build-arg REACT_APP_API_BASE_URL=https://staging.ai.pipexerp.com/api/v1 \
|
||||
--build-arg REACT_APP_ENV=staging \
|
||||
-t saltthing123/ai-proj-frontend:test --push frontend/
|
||||
|
||||
# 部署到测试服务器
|
||||
ssh singapore "cd /opt/ai-project-staging && sudo docker-compose pull && sudo docker-compose up -d"
|
||||
```
|
||||
|
||||
### 部署到生产环境
|
||||
|
||||
```bash
|
||||
cd /path/to/new-ai-proj
|
||||
|
||||
# 构建后端 latest 镜像
|
||||
docker buildx build --platform linux/amd64 -f backend/Dockerfile --target production \
|
||||
-t saltthing123/ai-proj-backend:latest --push backend/
|
||||
|
||||
# 构建前端 latest 镜像
|
||||
docker buildx build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
|
||||
--build-arg REACT_APP_API_URL=https://ai.pipexerp.com/api/v1 \
|
||||
--build-arg REACT_APP_API_BASE_URL=https://ai.pipexerp.com/api/v1 \
|
||||
--build-arg REACT_APP_ENV=production \
|
||||
-t saltthing123/ai-proj-frontend:latest --push frontend/
|
||||
|
||||
# 部署到生产服务器
|
||||
ssh tools_ai_proj "cd /opt/ai-project && \
|
||||
docker compose -f deploy/tencent-cloud/docker-compose.dockerhub.yml pull && \
|
||||
docker compose -f deploy/tencent-cloud/docker-compose.dockerhub.yml up -d"
|
||||
```
|
||||
|
||||
## 新加坡服务器 Build(备选方案)
|
||||
|
||||
本地网络慢时,在新加坡服务器构建:
|
||||
|
||||
```bash
|
||||
# 后端
|
||||
ssh singapore "cd ~/projects/new-ai-proj && git pull && \
|
||||
docker build --platform linux/amd64 -f backend/Dockerfile --target production \
|
||||
-t saltthing123/ai-proj-backend:latest ./backend && \
|
||||
docker push saltthing123/ai-proj-backend:latest"
|
||||
|
||||
# 前端(生产)
|
||||
ssh singapore "cd ~/projects/new-ai-proj && \
|
||||
docker build --platform linux/amd64 -f frontend/Dockerfile.prod --target production \
|
||||
--build-arg REACT_APP_API_URL=https://ai.pipexerp.com/api/v1 \
|
||||
--build-arg REACT_APP_API_BASE_URL=https://ai.pipexerp.com/api/v1 \
|
||||
--build-arg REACT_APP_ENV=production \
|
||||
-t saltthing123/ai-proj-frontend:latest ./frontend && \
|
||||
docker push saltthing123/ai-proj-frontend:latest"
|
||||
```
|
||||
|
||||
## 自动部署(Webhook)
|
||||
|
||||
**状态**: 已启用 (2026-01-16)
|
||||
|
||||
```
|
||||
git push main → Gitea webhook → Jenkins ai-proj → 生产自动部署
|
||||
```
|
||||
|
||||
## 服务管理
|
||||
|
||||
```bash
|
||||
# 查看容器状态
|
||||
ssh tools_ai_proj "docker ps --format 'table {{.Names}}\t{{.Status}}'"
|
||||
|
||||
# 查看日志
|
||||
ssh tools_ai_proj "docker logs -f ai_backend_prod --tail 100"
|
||||
|
||||
# 重启服务
|
||||
ssh tools_ai_proj "docker restart ai_backend_prod"
|
||||
|
||||
# 健康检查
|
||||
curl -s https://ai.pipexerp.com/api/v1/health | jq .
|
||||
```
|
||||
|
||||
## 测试环境管理
|
||||
|
||||
```bash
|
||||
# 查看状态
|
||||
ssh singapore "sudo docker-compose -f /opt/ai-project-staging/docker-compose.yml ps"
|
||||
|
||||
# 查看日志
|
||||
ssh singapore "sudo docker logs -f ai_backend_staging --tail 100"
|
||||
|
||||
# 健康检查
|
||||
ssh singapore "curl -s -H 'Host: staging.ai.pipexerp.com' http://127.0.0.1/api/v1/health"
|
||||
```
|
||||
|
||||
## Docker Volumes 配置
|
||||
|
||||
**重要**: 数据卷必须标记为 `external: true`
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
postgres_prod_data:
|
||||
external: true
|
||||
name: ai-project_postgres_prod_data
|
||||
redis_prod_data:
|
||||
external: true
|
||||
name: ai-project_redis_prod_data
|
||||
```
|
||||
|
||||
## 数据库操作
|
||||
|
||||
```bash
|
||||
# 运行迁移
|
||||
ssh tools_ai_proj "cd /opt/ai-project/backend/migrations && \
|
||||
for file in \$(ls *.sql | grep -v _down.sql | sort); do \
|
||||
docker exec -i ai_postgres_prod psql -U ai_prod_user -d ai_project_prod < \"\$file\"; \
|
||||
done"
|
||||
|
||||
# 备份
|
||||
ssh tools_ai_proj "docker exec ai_postgres_prod pg_dump -U ai_prod_user ai_project_prod > /tmp/backup.sql"
|
||||
```
|
||||
|
||||
## 用户管理
|
||||
|
||||
> **重要**: 密码哈希必须使用 bcrypt **cost 12**,这是后端 `utils/password.go` 中的 `DefaultCost` 值。
|
||||
|
||||
### 创建用户完整流程
|
||||
|
||||
由于 bcrypt 哈希包含 `$` 字符会被 shell 解释,必须使用文件传输方式:
|
||||
|
||||
```bash
|
||||
# 1. 生成密码哈希(在有 Go 环境的机器上执行)
|
||||
cd /path/to/new-ai-proj/backend
|
||||
cat > /tmp/genhash.go << 'EOF'
|
||||
package main
|
||||
import ("fmt"; "golang.org/x/crypto/bcrypt")
|
||||
func main() {
|
||||
hash, _ := bcrypt.GenerateFromPassword([]byte("用户密码"), 12)
|
||||
fmt.Println(string(hash))
|
||||
}
|
||||
EOF
|
||||
HASH=$(go run /tmp/genhash.go)
|
||||
echo "Generated hash: $HASH"
|
||||
|
||||
# 2. 创建 SQL 文件
|
||||
cat > /tmp/create_user.sql << EOF
|
||||
INSERT INTO users (username, email, password_hash, user_type, role, status, created_at, updated_at)
|
||||
VALUES ('newuser', 'newuser@example.com', '$HASH', 'system', 'admin', 'active', NOW(), NOW());
|
||||
EOF
|
||||
|
||||
# 3. 传输并执行
|
||||
scp /tmp/create_user.sql tools_ai_proj:/tmp/
|
||||
ssh tools_ai_proj "docker cp /tmp/create_user.sql ai_postgres_prod:/tmp/ && \
|
||||
docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/create_user.sql"
|
||||
|
||||
# 4. 验证
|
||||
curl -s -X POST "https://ai.pipexerp.com/api/v1/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"newuser","password":"用户密码"}' | jq '.success'
|
||||
```
|
||||
|
||||
### 用户角色
|
||||
|
||||
| user_type | role | 权限 |
|
||||
|-----------|------|------|
|
||||
| system | admin | 系统管理员 |
|
||||
| system | user | 系统用户 |
|
||||
| tenant | admin | 租户管理员 |
|
||||
| tenant | user | 租户用户 |
|
||||
|
||||
### 重置密码
|
||||
|
||||
```bash
|
||||
# 生成新哈希并更新
|
||||
cd /path/to/new-ai-proj/backend
|
||||
HASH=$(go run -e 'package main; import ("fmt";"golang.org/x/crypto/bcrypt"); func main() { h,_:=bcrypt.GenerateFromPassword([]byte("新密码"),12); fmt.Println(string(h)) }' 2>/dev/null || cat > /tmp/h.go << 'E'
|
||||
package main
|
||||
import ("fmt";"golang.org/x/crypto/bcrypt")
|
||||
func main() { h,_:=bcrypt.GenerateFromPassword([]byte("新密码"),12); fmt.Println(string(h)) }
|
||||
E
|
||||
go run /tmp/h.go)
|
||||
|
||||
cat > /tmp/reset.sql << EOF
|
||||
UPDATE users SET password_hash = '$HASH' WHERE username = 'targetuser';
|
||||
EOF
|
||||
|
||||
scp /tmp/reset.sql tools_ai_proj:/tmp/
|
||||
ssh tools_ai_proj "docker cp /tmp/reset.sql ai_postgres_prod:/tmp/ && \
|
||||
docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/reset.sql"
|
||||
```
|
||||
|
||||
### 常见错误
|
||||
|
||||
| 问题 | 原因 | 解决 |
|
||||
|------|------|------|
|
||||
| 登录失败 | bcrypt cost 不是 12 | 用 Go 重新生成 cost 12 的哈希 |
|
||||
| 哈希被截断 | shell 解释了 $ 符号 | 使用文件传输方式 |
|
||||
|
||||
### 已创建的系统用户
|
||||
|
||||
| 用户名 | 邮箱 | user_type | role | 创建时间 |
|
||||
|--------|------|-----------|------|----------|
|
||||
| qiudl | qiudl@zhiyuncai.com | system | admin | - |
|
||||
| jiaxiang | jiaxiang@joylodging.com | system | admin | 2026-01 |
|
||||
| haiqing | haiqing@joylodging.com | system | admin | 2026-02 |
|
||||
|
||||
> 注意:密码信息不在文档中记录,如需重置请使用上述重置密码流程
|
||||
|
||||
## 前端构建注意事项
|
||||
|
||||
必须同时设置两个 URL 变量:
|
||||
- `REACT_APP_API_URL`
|
||||
- `REACT_APP_API_BASE_URL`
|
||||
|
||||
否则会使用 `.env.production` 中的生产 URL。
|
||||
|
||||
验证镜像中的 URL:
|
||||
```bash
|
||||
docker exec <container> sh -c 'grep -oE "https://[a-zA-Z0-9.-]*pipexerp[a-zA-Z0-9./-]*" /usr/share/nginx/html/static/js/main*.js | sort | uniq -c'
|
||||
```
|
||||
@@ -1,100 +0,0 @@
|
||||
# Coolbuy-PaaS 部署指南
|
||||
|
||||
**创建时间**: 2026-01-29 11:50:00 CST
|
||||
**父技能**: ops-tools
|
||||
|
||||
## 仓库信息
|
||||
|
||||
| 仓库 | 地址 | 说明 |
|
||||
|------|------|------|
|
||||
| coolbuy-paas | git@gitea.pipexerp.com:pipexerp/coolbuy-paas.git | 租户业务系统 |
|
||||
| coolbuy-platform | git@gitea.pipexerp.com:pipexerp/coolbuy-platform.git | 平台管理端 |
|
||||
| coolbuy-legacy | git@gitea.pipexerp.com:pipexerp/coolbuy-legacy.git | 遗留项目 |
|
||||
|
||||
## 镜像信息
|
||||
|
||||
| 服务 | 镜像 | Dockerfile |
|
||||
|------|------|------------|
|
||||
| Auth | saltthing123/coolbuy-paas-auth | auth-service/Dockerfile |
|
||||
| Foundation | saltthing123/coolbuy-paas-foundation | foundation-service/Dockerfile |
|
||||
| ERP | saltthing123/coolbuy-paas-erp | erp-service/Dockerfile |
|
||||
| Web | saltthing123/coolbuy-paas-web | web/Dockerfile |
|
||||
|
||||
## 生产环境
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 服务器 IP | 39.106.88.83 |
|
||||
| 架构 | AMD64 |
|
||||
| 部署目录 | /opt/coolbuy-paas |
|
||||
| Web 端口 | 8888 |
|
||||
|
||||
## 部署流程(本地构建 + Jenkins 部署)
|
||||
|
||||
### 步骤 1: 本地构建并推送
|
||||
|
||||
```bash
|
||||
cd /path/to/coolbuy-paas
|
||||
|
||||
# 构建单个服务(AMD64 架构)
|
||||
docker buildx build --platform linux/amd64 -t saltthing123/coolbuy-paas-web:latest ./web --push
|
||||
|
||||
# 构建所有服务
|
||||
./scripts/build-and-push.sh --push --platform linux/amd64
|
||||
```
|
||||
|
||||
### 步骤 2: 触发 Jenkins 部署
|
||||
|
||||
```bash
|
||||
source ~/.config/devops/credentials.env
|
||||
|
||||
# 部署到生产
|
||||
curl -X POST "$JENKINS_URL/job/coolbuy-paas/buildWithParameters" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" \
|
||||
--data "ACTION=deploy-prod&IMAGE_TAG=latest"
|
||||
|
||||
# 部署到测试
|
||||
curl -X POST "$JENKINS_URL/job/coolbuy-paas/buildWithParameters" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" \
|
||||
--data "ACTION=deploy-test&IMAGE_TAG=latest"
|
||||
```
|
||||
|
||||
### 一键部署命令
|
||||
|
||||
```bash
|
||||
cd /path/to/coolbuy-paas && \
|
||||
docker buildx build --platform linux/amd64 -t saltthing123/coolbuy-paas-web:latest ./web --push && \
|
||||
source ~/.config/devops/credentials.env && \
|
||||
curl -X POST "$JENKINS_URL/job/coolbuy-paas/buildWithParameters" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" \
|
||||
--data "ACTION=deploy-prod&IMAGE_TAG=latest"
|
||||
```
|
||||
|
||||
## 查看构建状态
|
||||
|
||||
```bash
|
||||
source ~/.config/devops/credentials.env
|
||||
|
||||
# 构建状态
|
||||
curl -s "$JENKINS_URL/job/coolbuy-paas/lastBuild/api/json" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" | jq '.result, .building'
|
||||
|
||||
# 构建日志
|
||||
curl -s "$JENKINS_URL/job/coolbuy-paas/lastBuild/consoleText" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" | tail -50
|
||||
```
|
||||
|
||||
## 检查镜像架构
|
||||
|
||||
```bash
|
||||
# 本地镜像
|
||||
docker inspect saltthing123/coolbuy-paas-web:latest | grep Architecture
|
||||
|
||||
# DockerHub 镜像
|
||||
docker manifest inspect saltthing123/coolbuy-paas-web:latest | grep architecture
|
||||
```
|
||||
|
||||
## 重要提醒
|
||||
|
||||
- 生产服务器为 AMD64 架构,必须使用 `--platform linux/amd64`
|
||||
- 禁止在 Jenkins 服务器构建镜像,所有镜像本地构建后推送到 DockerHub
|
||||
@@ -1,837 +0,0 @@
|
||||
# 数据库备份与恢复 Skill
|
||||
|
||||
**父技能**: ops-tools
|
||||
**适用范围**: 全局(所有项目数据库)
|
||||
**创建时间**: 2026-01-15 07:30:00 ACDT
|
||||
**最后更新**: 2026-02-02
|
||||
|
||||
---
|
||||
|
||||
## 技能概述
|
||||
|
||||
全局数据库备份技能,适用于所有项目的 PostgreSQL 数据库。涵盖迁移前备份、自动备份、数据恢复和灾难恢复策略。
|
||||
|
||||
**核心原则**:
|
||||
- ⚠️ **任何数据库迁移操作前必须先备份**
|
||||
- 保留策略:最近 7 天 + 每月 1 个永久备份
|
||||
- 存储位置:服务器本地 `/backup/` 目录
|
||||
|
||||
---
|
||||
|
||||
## 数据库清单
|
||||
|
||||
| 数据库 | 服务器 | 容器 | 用途 | 备份路径 |
|
||||
|--------|--------|------|------|----------|
|
||||
| ai_project_prod | tools_ai_proj | ai_postgres_prod | AI-Proj 生产 | /backup/ai-project/database/ |
|
||||
| ai_project_staging | singapore | ai_postgres_staging | AI-Proj 测试 | /backup/ai-project-staging/ |
|
||||
| coolbuy_prod | coolbuy-dev | postgres | Coolbuy 3.0 | /backup/coolbuy/ |
|
||||
|
||||
---
|
||||
|
||||
## ⚡ 迁移前快速备份(必读)
|
||||
|
||||
> **重要**:执行任何 `UPDATE`、`DELETE`、`ALTER`、数据迁移等操作前,**必须先执行备份**。
|
||||
|
||||
### 一键备份命令
|
||||
|
||||
```bash
|
||||
# AI-Proj 生产数据库 - 迁移前备份
|
||||
ssh tools_ai_proj 'REASON="pre_migration_$(date +%Y%m%d_%H%M%S)" && \
|
||||
docker exec ai_postgres_prod pg_dump -U ai_prod_user -Fc ai_project_prod \
|
||||
> /backup/ai-project/database/ai_project_${REASON}.dump && \
|
||||
echo "✓ 备份完成: /backup/ai-project/database/ai_project_${REASON}.dump"'
|
||||
|
||||
# AI-Proj 测试数据库 - 迁移前备份
|
||||
ssh singapore 'REASON="pre_migration_$(date +%Y%m%d_%H%M%S)" && \
|
||||
sudo docker exec ai_postgres_staging pg_dump -U ai_staging_user -Fc ai_project_staging \
|
||||
> /backup/ai-project-staging/ai_project_staging_${REASON}.dump && \
|
||||
echo "✓ 备份完成"'
|
||||
```
|
||||
|
||||
### 带原因的备份(推荐)
|
||||
|
||||
```bash
|
||||
# 指定备份原因,方便追溯
|
||||
ssh tools_ai_proj 'REASON="migrate_project_165_to_167" && \
|
||||
docker exec ai_postgres_prod pg_dump -U ai_prod_user -Fc ai_project_prod \
|
||||
> /backup/ai-project/database/ai_project_$(date +%Y%m%d_%H%M%S)_${REASON}.dump && \
|
||||
ls -lh /backup/ai-project/database/ | tail -3'
|
||||
```
|
||||
|
||||
### 备份后验证
|
||||
|
||||
```bash
|
||||
# 验证备份文件
|
||||
ssh tools_ai_proj 'ls -lh /backup/ai-project/database/ | tail -5'
|
||||
|
||||
# 检查备份文件大小(应该 > 10MB)
|
||||
ssh tools_ai_proj 'stat --printf="%s bytes\n" /backup/ai-project/database/ai_project_*.dump | tail -1'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 快速恢复命令
|
||||
|
||||
### 从最新备份恢复
|
||||
|
||||
```bash
|
||||
# 1. 找到最新备份
|
||||
ssh tools_ai_proj 'ls -lt /backup/ai-project/database/*.dump | head -3'
|
||||
|
||||
# 2. 恢复(使用 pg_restore)
|
||||
ssh tools_ai_proj 'BACKUP_FILE="/backup/ai-project/database/ai_project_XXXXXXXX.dump" && \
|
||||
docker stop ai_backend_prod && \
|
||||
docker exec ai_postgres_prod pg_restore -U ai_prod_user -d ai_project_prod --clean --if-exists -Fc "$BACKUP_FILE" && \
|
||||
docker start ai_backend_prod && \
|
||||
echo "✓ 恢复完成"'
|
||||
|
||||
# 3. 验证
|
||||
curl -s https://ai.pipexerp.com/api/v1/health | jq .
|
||||
```
|
||||
|
||||
### 恢复到特定时间点
|
||||
|
||||
```bash
|
||||
# 列出所有备份,找到目标时间点
|
||||
ssh tools_ai_proj 'ls -lht /backup/ai-project/database/*.dump'
|
||||
|
||||
# 恢复指定备份
|
||||
ssh tools_ai_proj 'docker exec ai_postgres_prod pg_restore \
|
||||
-U ai_prod_user -d ai_project_prod --clean --if-exists -Fc \
|
||||
/backup/ai-project/database/ai_project_20260202_180000_migrate_project_165_to_167.dump'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 保留策略
|
||||
|
||||
### 策略说明
|
||||
|
||||
| 类型 | 保留时间 | 清理规则 |
|
||||
|------|----------|----------|
|
||||
| 每日备份 | 7 天 | 超过 7 天自动删除 |
|
||||
| 月度备份 | 永久 | 每月 1 号的备份永久保留 |
|
||||
| 迁移前备份 | 30 天 | 带 `pre_migration` 标记的保留 30 天 |
|
||||
|
||||
### 自动清理脚本
|
||||
|
||||
```bash
|
||||
# /opt/scripts/cleanup-backups.sh
|
||||
#!/bin/bash
|
||||
BACKUP_DIR="/backup/ai-project/database"
|
||||
|
||||
# 删除超过 7 天的每日备份(保留月度备份)
|
||||
find "$BACKUP_DIR" -name "*.dump" -mtime +7 ! -name "*_01_*" -delete
|
||||
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 ! -name "*_01_*" -delete
|
||||
|
||||
# 删除超过 30 天的迁移前备份
|
||||
find "$BACKUP_DIR" -name "*pre_migration*" -mtime +30 -delete
|
||||
|
||||
echo "$(date): Cleanup completed" >> /var/log/backup-cleanup.log
|
||||
```
|
||||
|
||||
### Cron 配置
|
||||
|
||||
```cron
|
||||
# 每天凌晨 3 点清理旧备份
|
||||
0 3 * * * /opt/scripts/cleanup-backups.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 快速参考
|
||||
|
||||
| 操作 | 命令 |
|
||||
|------|------|
|
||||
| 手动执行备份 | `ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-database.sh"` |
|
||||
| 查看本地备份 | `ssh tools_ai_proj "ls -lh /backup/ai-project/database/"` |
|
||||
| 查看备份日志 | `ssh tools_ai_proj "tail -f /var/log/ai-project-backup.log"` |
|
||||
| 触发 OSS 同步 | `ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-to-oss.sh"` |
|
||||
| 列出 OSS 备份 | `ssh tools_ai_proj "ossutil ls oss://fnos2026/ai-project/backups/ --config-file ~/.ossutilconfig"` |
|
||||
| 下载最新备份 | `ssh tools_ai_proj "ossutil cp oss://fnos2026/ai-project/backups/latest.sql.gz /tmp/ --config-file ~/.ossutilconfig"` |
|
||||
| 验证备份完整性 | `ssh tools_ai_proj "gzip -t /backup/ai-project/database/latest.sql.gz"` |
|
||||
|
||||
---
|
||||
|
||||
## 备份架构
|
||||
|
||||
### 双层备份策略
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ AI-Proj 生产服务器 │
|
||||
│ (tools_ai_proj: 152.136.104.251) │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ PostgreSQL 数据库 (ai_postgres_prod) │
|
||||
│ │ │
|
||||
│ │ 每天 02:00 (Cron) │
|
||||
│ ▼ │
|
||||
│ 本地备份 (/backup/ai-project/database/) │
|
||||
│ │ - gzip 压缩 │
|
||||
│ │ - 30 天保留 │
|
||||
│ │ - 完整性验证 │
|
||||
│ │ - 符号链接 (latest.sql.gz) │
|
||||
│ │ │
|
||||
│ │ 每天 02:30 (Cron) │
|
||||
│ ▼ │
|
||||
│ OSS 同步 (backup-to-oss.sh) │
|
||||
│ │ │
|
||||
└────────────┼─────────────────────────────────────────────┘
|
||||
│
|
||||
│ 互联网 (623 KB/s)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 阿里云对象存储 (OSS) │
|
||||
│ 北京区域 │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ Bucket: fnos2026 │
|
||||
│ 路径: /ai-project/backups/ │
|
||||
│ │
|
||||
│ ├── YYYYMMDD/ │
|
||||
│ │ └── ai_project_YYYYMMDD_HHMMSS.sql.gz │
|
||||
│ └── latest.sql.gz (最新备份) │
|
||||
│ │
|
||||
│ ✅ 异地容灾 (99.9% 可用性) │
|
||||
│ ✅ 30 天自动清理 │
|
||||
│ ✅ 成本: ~¥0.25/月 │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 备份时间表
|
||||
|
||||
| 时间 | 操作 | 脚本 | 日志文件 |
|
||||
|------|------|------|----------|
|
||||
| 02:00 | 本地数据库备份 | `/opt/ai-project/deploy/scripts/backup-database.sh` | `/var/log/ai-project-backup.log` |
|
||||
| 02:30 | OSS 异地同步 | `/opt/ai-project/deploy/scripts/backup-to-oss.sh` | `/var/log/ai-project-oss-sync.log` |
|
||||
|
||||
---
|
||||
|
||||
## 自动备份配置
|
||||
|
||||
### 本地备份
|
||||
|
||||
**脚本位置**: `/opt/ai-project/deploy/scripts/backup-database.sh`
|
||||
|
||||
**功能特性**:
|
||||
- ✅ PostgreSQL pg_dump 完整备份
|
||||
- ✅ gzip 压缩
|
||||
- ✅ 按日期目录组织
|
||||
- ✅ 30 天自动清理
|
||||
- ✅ 备份完整性验证
|
||||
- ✅ 符号链接指向最新备份
|
||||
|
||||
**Cron 配置**:
|
||||
```cron
|
||||
0 2 * * * /opt/ai-project/deploy/scripts/backup-database.sh >> /var/log/ai-project-backup.log 2>&1
|
||||
```
|
||||
|
||||
**手动执行**:
|
||||
```bash
|
||||
ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-database.sh"
|
||||
```
|
||||
|
||||
**查看日志**:
|
||||
```bash
|
||||
ssh tools_ai_proj "tail -f /var/log/ai-project-backup.log"
|
||||
```
|
||||
|
||||
**备份目录结构**:
|
||||
```
|
||||
/backup/ai-project/database/
|
||||
├── 20260115/
|
||||
│ ├── ai_project_20260115_020001.sql.gz (13M)
|
||||
│ └── ai_project_20260115_120000.sql.gz (13M)
|
||||
├── 20260116/
|
||||
│ └── ai_project_20260116_020001.sql.gz (13M)
|
||||
└── latest.sql.gz -> 20260116/ai_project_20260116_020001.sql.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 阿里云 OSS 异地备份
|
||||
|
||||
**配置时间**: 2026-01-15 01:12:00 CST
|
||||
**首次同步**: 2026-01-15 02:30:01 CST
|
||||
|
||||
### OSS 配置信息
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| Endpoint | oss-cn-beijing.aliyuncs.com |
|
||||
| Bucket | fnos2026 |
|
||||
| 存储路径 | oss://fnos2026/ai-project/backups/ |
|
||||
| 保留策略 | 30 天自动清理 |
|
||||
| 预计成本 | ~¥0.25/月 |
|
||||
|
||||
### 凭据配置
|
||||
|
||||
**存储位置**: `~/.config/devops/credentials.env` (权限 600)
|
||||
|
||||
```bash
|
||||
OSS_ENDPOINT="oss-cn-beijing.aliyuncs.com"
|
||||
OSS_BUCKET="fnos2026"
|
||||
OSS_ACCESS_KEY_ID="LTAI5tEARCztp3Bj3FUYd9rh"
|
||||
OSS_ACCESS_KEY_SECRET="RSvwURFo2cgF1krSgeriyrAUIqQyGE"
|
||||
```
|
||||
|
||||
**加载凭据**:
|
||||
```bash
|
||||
source ~/.config/devops/credentials.env
|
||||
```
|
||||
|
||||
### ossutil 工具
|
||||
|
||||
**版本**: v1.7.15
|
||||
**安装位置**: `/usr/local/bin/ossutil`
|
||||
**安装时间**: 2026-01-15 00:45:00 CST
|
||||
|
||||
**安装步骤**:
|
||||
```bash
|
||||
wget https://gosspublic.alicdn.com/ossutil/1.7.15/ossutil64
|
||||
sudo mv ossutil64 /usr/local/bin/ossutil
|
||||
sudo chmod +x /usr/local/bin/ossutil
|
||||
```
|
||||
|
||||
**配置**:
|
||||
```bash
|
||||
source ~/.config/devops/credentials.env
|
||||
ossutil config -e ${OSS_ENDPOINT} \
|
||||
-i ${OSS_ACCESS_KEY_ID} \
|
||||
-k ${OSS_ACCESS_KEY_SECRET} \
|
||||
-L CH \
|
||||
--config-file ~/.ossutilconfig
|
||||
```
|
||||
|
||||
**测试连接**:
|
||||
```bash
|
||||
ossutil ls oss://${OSS_BUCKET}/
|
||||
```
|
||||
|
||||
### 自动同步脚本
|
||||
|
||||
**脚本位置**: `/opt/ai-project/deploy/scripts/backup-to-oss.sh`
|
||||
|
||||
**功能特性**:
|
||||
- ✅ 同步当天备份目录到 OSS
|
||||
- ✅ 上传 latest.sql.gz
|
||||
- ✅ 自动清理 30 天前的旧备份
|
||||
- ✅ 备份统计报告
|
||||
- ✅ 彩色日志输出
|
||||
|
||||
**Cron 配置**:
|
||||
```cron
|
||||
30 2 * * * /opt/ai-project/deploy/scripts/backup-to-oss.sh >> /var/log/ai-project-oss-sync.log 2>&1
|
||||
```
|
||||
|
||||
**手动执行**:
|
||||
```bash
|
||||
ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-to-oss.sh"
|
||||
```
|
||||
|
||||
**查看日志**:
|
||||
```bash
|
||||
ssh tools_ai_proj "tail -f /var/log/ai-project-oss-sync.log"
|
||||
```
|
||||
|
||||
### 常用 OSS 操作
|
||||
|
||||
```bash
|
||||
# 加载凭据
|
||||
source ~/.config/devops/credentials.env
|
||||
|
||||
# 列出所有备份文件
|
||||
ssh tools_ai_proj "ossutil ls oss://${OSS_BUCKET}/ai-project/backups/ -r --config-file ~/.ossutilconfig"
|
||||
|
||||
# 查看备份统计
|
||||
ssh tools_ai_proj "ossutil du oss://${OSS_BUCKET}/ai-project/backups/ --config-file ~/.ossutilconfig"
|
||||
|
||||
# 下载特定日期的备份
|
||||
ssh tools_ai_proj "ossutil cp oss://${OSS_BUCKET}/ai-project/backups/20260115/ai_project_20260115_*.sql.gz /tmp/ --config-file ~/.ossutilconfig"
|
||||
|
||||
# 下载最新备份
|
||||
ssh tools_ai_proj "ossutil cp oss://${OSS_BUCKET}/ai-project/backups/latest.sql.gz /tmp/ --config-file ~/.ossutilconfig"
|
||||
|
||||
# 查看备份文件详情
|
||||
ssh tools_ai_proj "ossutil stat oss://${OSS_BUCKET}/ai-project/backups/latest.sql.gz --config-file ~/.ossutilconfig"
|
||||
|
||||
# 手动清理特定日期的备份
|
||||
ssh tools_ai_proj "ossutil rm oss://${OSS_BUCKET}/ai-project/backups/20260101/ -r -f --config-file ~/.ossutilconfig"
|
||||
```
|
||||
|
||||
### 备份验证
|
||||
|
||||
```bash
|
||||
# 验证最新备份是否上传成功
|
||||
ssh tools_ai_proj "ossutil stat oss://${OSS_BUCKET}/ai-project/backups/latest.sql.gz --config-file ~/.ossutilconfig"
|
||||
|
||||
# 下载并测试备份完整性
|
||||
ssh tools_ai_proj "
|
||||
ossutil cp oss://${OSS_BUCKET}/ai-project/backups/latest.sql.gz /tmp/test_restore.sql.gz --config-file ~/.ossutilconfig
|
||||
gzip -t /tmp/test_restore.sql.gz && echo '✓ 备份文件完整' || echo '✗ 备份文件损坏'
|
||||
rm /tmp/test_restore.sql.gz
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 手动备份
|
||||
|
||||
### 完整备份
|
||||
|
||||
```bash
|
||||
# 连接到生产服务器
|
||||
ssh tools_ai_proj
|
||||
|
||||
# 导出数据库
|
||||
docker exec ai_postgres_prod pg_dump -U ai_prod_user ai_project_prod \
|
||||
--no-owner --no-acl --clean --if-exists \
|
||||
> /tmp/ai_project_backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
|
||||
# 压缩备份
|
||||
gzip /tmp/ai_project_backup_*.sql
|
||||
|
||||
# 验证备份完整性
|
||||
gzip -t /tmp/ai_project_backup_*.sql.gz
|
||||
```
|
||||
|
||||
### 下载到本地
|
||||
|
||||
**直接下载** (如果网络良好):
|
||||
```bash
|
||||
scp tools_ai_proj:/tmp/ai_project_backup_*.sql.gz /tmp/
|
||||
```
|
||||
|
||||
**通过跳板机优化传输** (高延迟环境):
|
||||
```bash
|
||||
# 使用新加坡跳板机中转(澳洲 → 新加坡 → 腾讯云)
|
||||
scp tools_ai_proj:/tmp/ai_project_backup_*.sql.gz singapore:/tmp/
|
||||
scp singapore:/tmp/ai_project_backup_*.sql.gz /tmp/
|
||||
|
||||
# 清理跳板机临时文件
|
||||
ssh singapore "rm /tmp/ai_project_backup_*.sql.gz"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 数据库恢复
|
||||
|
||||
### 场景 1: 从 OSS 备份恢复(推荐)
|
||||
|
||||
```bash
|
||||
# 1. 从 OSS 下载最新备份
|
||||
ssh tools_ai_proj "
|
||||
source ~/.config/devops/credentials.env
|
||||
ossutil cp oss://fnos2026/ai-project/backups/latest.sql.gz /tmp/restore.sql.gz --config-file ~/.ossutilconfig -f
|
||||
"
|
||||
|
||||
# 2. 验证文件完整性
|
||||
ssh tools_ai_proj "gzip -t /tmp/restore.sql.gz"
|
||||
|
||||
# 3. 停止后端服务
|
||||
ssh tools_ai_proj "docker stop ai_backend_prod"
|
||||
|
||||
# 4. 恢复数据库
|
||||
ssh tools_ai_proj "
|
||||
gunzip -c /tmp/restore.sql.gz | \
|
||||
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod
|
||||
"
|
||||
|
||||
# 5. 启动后端服务
|
||||
ssh tools_ai_proj "docker start ai_backend_prod"
|
||||
|
||||
# 6. 验证服务
|
||||
curl -s https://ai.pipexerp.com/api/v1/health | jq .
|
||||
|
||||
# 7. 清理临时文件
|
||||
ssh tools_ai_proj "rm /tmp/restore.sql.gz"
|
||||
```
|
||||
|
||||
### 场景 2: 从本地备份恢复
|
||||
|
||||
```bash
|
||||
ssh tools_ai_proj
|
||||
|
||||
# 停止后端服务
|
||||
docker stop ai_backend_prod
|
||||
|
||||
# 恢复数据库
|
||||
gunzip -c /backup/ai-project/database/latest.sql.gz | \
|
||||
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod
|
||||
|
||||
# 启动后端服务
|
||||
docker start ai_backend_prod
|
||||
```
|
||||
|
||||
### 场景 3: 从本地开发环境恢复到生产(完整重建)
|
||||
|
||||
```bash
|
||||
# 1. 本地导出
|
||||
pg_dump -U donglinlai ai_project_local \
|
||||
--no-owner --no-acl --clean --if-exists \
|
||||
--exclude-table=audit_logs \
|
||||
> /tmp/ai_project_clean.sql
|
||||
|
||||
# 2. 压缩
|
||||
gzip /tmp/ai_project_clean.sql
|
||||
|
||||
# 3. 通过新加坡跳板机传输(优化高延迟)
|
||||
scp /tmp/ai_project_clean.sql.gz singapore:/tmp/
|
||||
ssh singapore "scp /tmp/ai_project_clean.sql.gz tools_ai_proj:/tmp/"
|
||||
|
||||
# 4. 生产环境恢复
|
||||
ssh tools_ai_proj
|
||||
|
||||
# 停止后端服务
|
||||
docker stop ai_backend_prod
|
||||
|
||||
# 完全重建数据库(避免依赖冲突)
|
||||
docker exec ai_postgres_prod psql -U ai_prod_user postgres \
|
||||
-c 'DROP DATABASE IF EXISTS ai_project_prod;'
|
||||
|
||||
docker exec ai_postgres_prod psql -U ai_prod_user postgres \
|
||||
-c 'CREATE DATABASE ai_project_prod OWNER ai_prod_user;'
|
||||
|
||||
# 恢复数据
|
||||
gunzip -c /tmp/ai_project_clean.sql.gz | \
|
||||
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod
|
||||
|
||||
# 创建可能缺失的表
|
||||
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod << 'EOF'
|
||||
CREATE TABLE IF NOT EXISTS audit_logs (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER,
|
||||
action VARCHAR(100),
|
||||
resource_type VARCHAR(100),
|
||||
resource_id VARCHAR(100),
|
||||
details TEXT,
|
||||
ip_address VARCHAR(50),
|
||||
user_agent TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
EOF
|
||||
|
||||
# 运行数据库迁移(如果有)
|
||||
cd /opt/ai-project/backend/migrations
|
||||
for file in $(ls *.sql | grep -v _down.sql | sort); do
|
||||
echo "Running migration: $file"
|
||||
docker exec -i ai_postgres_prod psql -U ai_prod_user ai_project_prod < "$file"
|
||||
done
|
||||
|
||||
# 启动后端服务
|
||||
docker start ai_backend_prod
|
||||
|
||||
# 清理临时文件
|
||||
rm /tmp/ai_project_clean.sql.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### Docker Volumes 安全配置
|
||||
|
||||
**关键规则**: 所有生产数据卷必须配置为 `external: true`
|
||||
|
||||
**正确配置** (`deploy/tencent-cloud/docker-compose.dockerhub.yml`):
|
||||
```yaml
|
||||
volumes:
|
||||
postgres_prod_data:
|
||||
external: true
|
||||
name: ai-project_postgres_prod_data
|
||||
redis_prod_data:
|
||||
external: true
|
||||
name: ai-project_redis_prod_data
|
||||
```
|
||||
|
||||
**危险配置** (会被 `docker compose down` 删除):
|
||||
```yaml
|
||||
volumes:
|
||||
postgres_prod_data:
|
||||
redis_prod_data:
|
||||
```
|
||||
|
||||
**验证**:
|
||||
```bash
|
||||
ssh tools_ai_proj "docker volume ls | grep ai-project"
|
||||
# 应该看到:
|
||||
# ai-project_postgres_prod_data
|
||||
# ai-project_redis_prod_data
|
||||
```
|
||||
|
||||
### 备份策略
|
||||
|
||||
1. **每日自动备份** - 使用 cron 定时任务
|
||||
2. **双层备份** - 本地 + 阿里云 OSS
|
||||
3. **定期验证** - 每周测试备份恢复流程
|
||||
4. **保留策略** - 30 天自动清理
|
||||
|
||||
### pg_dump 最佳参数
|
||||
|
||||
```bash
|
||||
# 跨服务器迁移
|
||||
pg_dump --no-owner --no-acl --clean --if-exists --exclude-table=<problem_table>
|
||||
|
||||
# 参数说明:
|
||||
# --no-owner 不恢复对象所有者(避免用户名冲突)
|
||||
# --no-acl 不恢复访问权限(避免权限问题)
|
||||
# --clean 包含 DROP 语句(完全替换)
|
||||
# --if-exists DROP 前检查存在(避免错误)
|
||||
# --exclude-table 排除问题表(如有 JSON 格式问题的表)
|
||||
```
|
||||
|
||||
### 数据恢复检查清单
|
||||
|
||||
在执行恢复前,务必检查以下项目:
|
||||
|
||||
- [ ] 确认备份文件完整性(gzip -t 验证)
|
||||
- [ ] 停止相关应用服务(避免数据不一致)
|
||||
- [ ] 完全重建数据库(DROP + CREATE,避免依赖冲突)
|
||||
- [ ] 恢复后创建缺失的表(如被排除的表)
|
||||
- [ ] 运行数据库迁移(确保表结构最新)
|
||||
- [ ] 验证数据完整性(检查关键表行数)
|
||||
- [ ] 测试应用功能(登录、关键业务流程)
|
||||
- [ ] 清理临时文件(备份文件、SQL 文件)
|
||||
|
||||
### 网络传输优化
|
||||
|
||||
**场景**: 跨地域高延迟环境(如澳洲 → 腾讯云)
|
||||
|
||||
**问题**: 直连延迟 370ms+,大文件传输极慢
|
||||
|
||||
**方案**: 使用地理位置中间的跳板机
|
||||
|
||||
```bash
|
||||
# 直连(慢): 澳洲 → 腾讯云 (370ms+)
|
||||
scp file.gz tools_ai_proj:/tmp/
|
||||
|
||||
# 优化(快): 澳洲 → 新加坡 → 腾讯云
|
||||
scp file.gz singapore:/tmp/
|
||||
ssh singapore "scp /tmp/file.gz tools_ai_proj:/tmp/"
|
||||
```
|
||||
|
||||
**新加坡跳板机信息**:
|
||||
- 别名: singapore
|
||||
- IP: 43.134.28.147
|
||||
- 用户: ubuntu
|
||||
- SSH Key: ~/.ssh/singpore.pem
|
||||
|
||||
---
|
||||
|
||||
## 监控与告警
|
||||
|
||||
### 每周检查清单
|
||||
|
||||
**建议执行频率**: 每周一次
|
||||
|
||||
```bash
|
||||
# 1. 检查本地备份
|
||||
ssh tools_ai_proj "ls -lh /backup/ai-project/database/$(date +%Y%m%d)/"
|
||||
|
||||
# 2. 检查 OSS 备份
|
||||
ssh tools_ai_proj "ossutil stat oss://fnos2026/ai-project/backups/latest.sql.gz --config-file ~/.ossutilconfig"
|
||||
|
||||
# 3. 检查 cron 日志
|
||||
ssh tools_ai_proj "tail -20 /var/log/ai-project-backup.log"
|
||||
ssh tools_ai_proj "tail -20 /var/log/ai-project-oss-sync.log"
|
||||
|
||||
# 4. 验证备份大小(应该在 10-20M 范围)
|
||||
ssh tools_ai_proj "du -sh /backup/ai-project/database/$(date +%Y%m%d)/"
|
||||
|
||||
# 5. 测试备份完整性
|
||||
ssh tools_ai_proj "
|
||||
gzip -t /backup/ai-project/database/latest.sql.gz && \
|
||||
echo '✓ 本地备份完整' || echo '✗ 本地备份损坏'
|
||||
"
|
||||
```
|
||||
|
||||
### 备份失败排查
|
||||
|
||||
如果备份或同步失败:
|
||||
|
||||
1. **检查磁盘空间**:
|
||||
```bash
|
||||
ssh tools_ai_proj "df -h"
|
||||
```
|
||||
|
||||
2. **检查 PostgreSQL 容器状态**:
|
||||
```bash
|
||||
ssh tools_ai_proj "docker ps | grep postgres"
|
||||
```
|
||||
|
||||
3. **检查 ossutil 配置**:
|
||||
```bash
|
||||
ssh tools_ai_proj "cat ~/.ossutilconfig"
|
||||
```
|
||||
|
||||
4. **测试 OSS 连接**:
|
||||
```bash
|
||||
ssh tools_ai_proj "ossutil ls oss://fnos2026/ --config-file ~/.ossutilconfig"
|
||||
```
|
||||
|
||||
5. **手动运行脚本查看详细错误**:
|
||||
```bash
|
||||
ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-database.sh"
|
||||
ssh tools_ai_proj "/opt/ai-project/deploy/scripts/backup-to-oss.sh"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 成本估算
|
||||
|
||||
**基于当前数据量** (13MB/天):
|
||||
|
||||
| 项目 | 计算 | 月成本 |
|
||||
|------|------|--------|
|
||||
| OSS 存储 | 13MB × 30天 = 390MB × ¥0.12/GB | ¥0.05 |
|
||||
| OSS 流量 | 13MB × 30天 = 390MB × ¥0.50/GB | ¥0.20 |
|
||||
| **总计** | | **¥0.25** |
|
||||
|
||||
---
|
||||
|
||||
## 故障案例
|
||||
|
||||
### 2026-01-15: 生产数据库丢失事件
|
||||
|
||||
**事件时间**: 2026-01-15 00:00:00 - 00:46:00 CST
|
||||
|
||||
**事件**: Jenkins 部署时 `docker compose down` 删除了非 external volumes
|
||||
|
||||
**影响**: 生产数据库完全清空,所有用户无法登录
|
||||
|
||||
**恢复过程**:
|
||||
1. 从本地开发环境导出完整数据(41 用户、54 项目、4,722 任务)
|
||||
2. 使用新加坡跳板机优化传输(解决 370ms+ 延迟)
|
||||
3. 完全重建数据库避免依赖冲突
|
||||
4. 重置所有管理员密码
|
||||
|
||||
**恢复完成时间**: 2026-01-15 00:46:00 CST
|
||||
|
||||
**预防措施**:
|
||||
1. ✅ 所有数据卷标记为 `external: true` (完成时间: 2026-01-15 00:46:00)
|
||||
2. ✅ Jenkinsfile 添加自动数据库迁移 (完成时间: 2026-01-15 00:46:00)
|
||||
3. ✅ 临时禁用 webhook 自动部署 (完成时间: 2026-01-15 00:46:00)
|
||||
4. ✅ 配置自动备份策略(本地 + OSS 双层备份)(完成时间: 2026-01-15 02:30:46)
|
||||
|
||||
**详细记录**: 见思源笔记 `devops/运维记录/2026-01-15 AI-Proj生产数据库恢复记录`
|
||||
|
||||
---
|
||||
|
||||
## 用户管理相关
|
||||
|
||||
数据库用户管理(创建用户、重置密码)请参考:
|
||||
- **ops-tools/SKILL.md** - "AI-Proj 用户管理" 章节
|
||||
- **ai-proj-deploy.md** - "用户管理" 章节
|
||||
|
||||
**关键注意事项**:
|
||||
- 密码哈希使用 bcrypt **cost 12**(后端 `utils/password.go` 的 `DefaultCost`)
|
||||
- 由于 `$` 字符问题,SQL 必须通过文件传输方式执行
|
||||
|
||||
---
|
||||
|
||||
## 相关资源
|
||||
|
||||
- **父技能**: ops-tools/skill.md
|
||||
- **备份脚本**: `/opt/ai-project/deploy/scripts/backup-database.sh`
|
||||
- **OSS 同步脚本**: `/opt/ai-project/deploy/scripts/backup-to-oss.sh`
|
||||
- **凭据文件**: `~/.config/devops/credentials.env`
|
||||
- **SiYuan 笔记**: `devops/运维记录/2026-01-15 AI-Proj生产数据库恢复记录`
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## 数据库迁移标准流程
|
||||
|
||||
> **强制要求**:任何数据库迁移操作必须遵循以下流程。
|
||||
|
||||
### 迁移检查清单
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 数据库迁移标准流程 │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ 1. 迁移前备份 ⬅️ 必须 │
|
||||
│ ssh tools_ai_proj 'docker exec ai_postgres_prod \ │
|
||||
│ pg_dump -U ai_prod_user -Fc ai_project_prod \ │
|
||||
│ > /backup/ai-project/database/pre_migration.dump' │
|
||||
│ │
|
||||
│ 2. 验证备份文件 │
|
||||
│ ssh tools_ai_proj 'ls -lh /backup/.../pre_migration.dump'│
|
||||
│ │
|
||||
│ 3. 记录迁移前状态 │
|
||||
│ SELECT COUNT(*) FROM <table>; │
|
||||
│ │
|
||||
│ 4. 执行迁移(使用事务) │
|
||||
│ BEGIN; ... COMMIT; │
|
||||
│ │
|
||||
│ 5. 验证迁移结果 │
|
||||
│ SELECT COUNT(*) FROM <table>; │
|
||||
│ │
|
||||
│ 6. 如有问题,恢复备份 │
|
||||
│ pg_restore -Fc pre_migration.dump │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 迁移 SQL 模板
|
||||
|
||||
```sql
|
||||
-- ============================================
|
||||
-- 迁移脚本模板
|
||||
-- 执行前请先备份!
|
||||
-- ============================================
|
||||
|
||||
BEGIN;
|
||||
|
||||
-- 迁移前统计
|
||||
\echo '=== 迁移前统计 ==='
|
||||
SELECT 'table_name' as info, COUNT(*) as count FROM table_name WHERE condition;
|
||||
|
||||
-- 执行迁移
|
||||
\echo '=== 执行迁移 ==='
|
||||
UPDATE table_name SET column = new_value WHERE condition;
|
||||
|
||||
-- 迁移后统计
|
||||
\echo '=== 迁移后统计 ==='
|
||||
SELECT 'table_name' as info, COUNT(*) as count FROM table_name WHERE condition;
|
||||
|
||||
-- 确认无误后提交
|
||||
COMMIT;
|
||||
|
||||
\echo '=== 迁移完成 ==='
|
||||
```
|
||||
|
||||
### 迁移失败回滚
|
||||
|
||||
```bash
|
||||
# 1. 停止后端服务
|
||||
ssh tools_ai_proj 'docker stop ai_backend_prod'
|
||||
|
||||
# 2. 恢复备份
|
||||
ssh tools_ai_proj 'docker exec ai_postgres_prod pg_restore \
|
||||
-U ai_prod_user -d ai_project_prod --clean --if-exists -Fc \
|
||||
/backup/ai-project/database/ai_project_XXXXXXXX_pre_migration.dump'
|
||||
|
||||
# 3. 启动后端服务
|
||||
ssh tools_ai_proj 'docker start ai_backend_prod'
|
||||
|
||||
# 4. 验证服务
|
||||
curl -s https://ai.pipexerp.com/api/v1/health | jq .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| 2.0 | 2026-02-02 | 升级为全局技能:新增迁移前备份流程、多数据库支持、7天+月度保留策略、快速恢复命令 |
|
||||
| 1.0 | 2026-01-15 | 初始版本:AI-Proj 备份与 OSS 同步 |
|
||||
|
||||
---
|
||||
|
||||
**文档创建时间**: 2026-01-15 07:30:00 ACDT
|
||||
**最后更新时间**: 2026-02-02
|
||||
**文档状态**: ✅ 正常运行
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 部署状态检查脚本
|
||||
# 用法: ./deploy-check.sh [ai-proj|pipeXerp]
|
||||
|
||||
set -e
|
||||
|
||||
TOOLS_SERVER="root@101.200.136.200"
|
||||
TOOLS_KEY="~/.ssh/tools.pem"
|
||||
JOB_NAME="${1:-ai-proj}"
|
||||
|
||||
echo "======================================"
|
||||
echo "Jenkins Job: $JOB_NAME"
|
||||
echo "======================================"
|
||||
|
||||
ssh -i $TOOLS_KEY -o ConnectTimeout=5 $TOOLS_SERVER << EOF
|
||||
echo "--- 最近 5 次构建 ---"
|
||||
ls -lt /var/lib/jenkins/jobs/$JOB_NAME/builds/ 2>/dev/null | head -6
|
||||
|
||||
echo ""
|
||||
echo "--- 最近成功构建 ---"
|
||||
if [ -L /var/lib/jenkins/jobs/$JOB_NAME/builds/lastSuccessfulBuild ]; then
|
||||
BUILD_NUM=\$(readlink /var/lib/jenkins/jobs/$JOB_NAME/builds/lastSuccessfulBuild)
|
||||
echo "Build #\$BUILD_NUM"
|
||||
if [ -f "/var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log" ]; then
|
||||
echo "构建时间: \$(stat -c %y /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log 2>/dev/null || stat -f %Sm /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log)"
|
||||
fi
|
||||
else
|
||||
echo "无成功构建记录"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- 最近失败构建 ---"
|
||||
if [ -L /var/lib/jenkins/jobs/$JOB_NAME/builds/lastFailedBuild ]; then
|
||||
BUILD_NUM=\$(readlink /var/lib/jenkins/jobs/$JOB_NAME/builds/lastFailedBuild)
|
||||
echo "Build #\$BUILD_NUM"
|
||||
echo "错误日志(最后 20 行):"
|
||||
tail -20 /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log 2>/dev/null || echo "无法读取日志"
|
||||
else
|
||||
echo "无失败构建记录"
|
||||
fi
|
||||
EOF
|
||||
@@ -1,97 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Gitea PR 操作脚本
|
||||
# 用法:
|
||||
# ./gitea-pr.sh list # 列出 PR
|
||||
# ./gitea-pr.sh create <title> <head> # 创建 PR
|
||||
# ./gitea-pr.sh merge <pr-number> # 合并 PR
|
||||
|
||||
set -e
|
||||
|
||||
# 加载凭据
|
||||
source ~/.config/devops/credentials.env
|
||||
|
||||
REPO="Tools/new-ai-proj"
|
||||
ACTION="${1:-list}"
|
||||
|
||||
case "$ACTION" in
|
||||
list)
|
||||
echo "=== 当前 Pull Requests ==="
|
||||
curl -s "$GITEA_URL/api/v1/repos/$REPO/pulls?state=open" \
|
||||
-H "Authorization: token $GITEA_TOKEN" | \
|
||||
python3 -c "
|
||||
import sys, json
|
||||
prs = json.load(sys.stdin)
|
||||
if not prs:
|
||||
print('没有开放的 PR')
|
||||
else:
|
||||
for pr in prs:
|
||||
print(f\"#{pr['number']} [{pr['state']}] {pr['title']}\")
|
||||
print(f\" {pr['head']['ref']} -> {pr['base']['ref']}\")
|
||||
print(f\" 作者: {pr['user']['login']}\")
|
||||
print()
|
||||
"
|
||||
;;
|
||||
|
||||
create)
|
||||
TITLE="$2"
|
||||
HEAD="$3"
|
||||
BASE="${4:-main}"
|
||||
|
||||
if [ -z "$TITLE" ] || [ -z "$HEAD" ]; then
|
||||
echo "用法: $0 create <title> <head-branch> [base-branch]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "创建 PR: $TITLE"
|
||||
echo "分支: $HEAD -> $BASE"
|
||||
|
||||
curl -s -X POST "$GITEA_URL/api/v1/repos/$REPO/pulls" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"title\":\"$TITLE\",\"head\":\"$HEAD\",\"base\":\"$BASE\"}" | \
|
||||
python3 -c "
|
||||
import sys, json
|
||||
pr = json.load(sys.stdin)
|
||||
if 'number' in pr:
|
||||
print(f\"PR 创建成功! #{pr['number']}\")
|
||||
print(f\"URL: {pr['html_url']}\")
|
||||
else:
|
||||
print(f\"创建失败: {pr.get('message', '未知错误')}\")
|
||||
"
|
||||
;;
|
||||
|
||||
merge)
|
||||
PR_NUM="$2"
|
||||
|
||||
if [ -z "$PR_NUM" ]; then
|
||||
echo "用法: $0 merge <pr-number>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "合并 PR #$PR_NUM..."
|
||||
|
||||
curl -s -X POST "$GITEA_URL/api/v1/repos/$REPO/pulls/$PR_NUM/merge" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"Do":"merge"}' | \
|
||||
python3 -c "
|
||||
import sys, json
|
||||
try:
|
||||
result = json.load(sys.stdin)
|
||||
if result:
|
||||
print(f\"结果: {result}\")
|
||||
else:
|
||||
print('PR 合并成功!')
|
||||
except:
|
||||
print('PR 合并成功!')
|
||||
"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "用法: $0 {list|create|merge}"
|
||||
echo " list - 列出所有开放的 PR"
|
||||
echo " create <title> <head> - 创建新 PR"
|
||||
echo " merge <pr-number> - 合并 PR"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,84 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 服务器健康检查脚本
|
||||
# 用法: ./health-check.sh [aliyun|website|all]
|
||||
|
||||
set -e
|
||||
|
||||
TOOLS_SERVER="root@101.200.136.200"
|
||||
TOOLS_KEY="~/.ssh/tools.pem"
|
||||
WEBSITE_SERVER="root@192.144.137.14"
|
||||
WEBSITE_KEY="~/.ssh/officialWebsite.pem"
|
||||
|
||||
check_tools_server() {
|
||||
echo "======================================"
|
||||
echo "Tools 服务器 (101.200.136.200)"
|
||||
echo "======================================"
|
||||
|
||||
ssh -i $TOOLS_KEY -o ConnectTimeout=5 $TOOLS_SERVER << 'EOF'
|
||||
echo "--- 系统负载 ---"
|
||||
uptime
|
||||
|
||||
echo ""
|
||||
echo "--- 内存使用 ---"
|
||||
free -h
|
||||
|
||||
echo ""
|
||||
echo "--- 磁盘使用 ---"
|
||||
df -h | grep -E '^/dev|Filesystem'
|
||||
|
||||
echo ""
|
||||
echo "--- Docker 容器 ---"
|
||||
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
|
||||
|
||||
echo ""
|
||||
echo "--- 系统服务 ---"
|
||||
echo -n "Jenkins: "; systemctl is-active jenkins
|
||||
echo -n "Nginx: "; systemctl is-active nginx
|
||||
echo -n "Docker: "; systemctl is-active docker
|
||||
|
||||
echo ""
|
||||
echo "--- 端口检查 ---"
|
||||
netstat -tlnp 2>/dev/null | grep -E ':3000|:8080|:10022|:5000' | awk '{print $4, $7}'
|
||||
EOF
|
||||
}
|
||||
|
||||
check_website_server() {
|
||||
echo "======================================"
|
||||
echo "Website 服务器 (192.144.137.14)"
|
||||
echo "======================================"
|
||||
|
||||
ssh -i $WEBSITE_KEY -o ConnectTimeout=5 $WEBSITE_SERVER << 'EOF'
|
||||
echo "--- 系统负载 ---"
|
||||
uptime
|
||||
|
||||
echo ""
|
||||
echo "--- 内存使用 ---"
|
||||
free -h
|
||||
|
||||
echo ""
|
||||
echo "--- 磁盘使用 ---"
|
||||
df -h | grep -E '^/dev|Filesystem'
|
||||
|
||||
echo ""
|
||||
echo "--- Nginx 状态 ---"
|
||||
systemctl is-active nginx || echo "nginx not running"
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-all}" in
|
||||
aliyun|tools)
|
||||
check_tools_server
|
||||
;;
|
||||
website)
|
||||
check_website_server
|
||||
;;
|
||||
all)
|
||||
check_tools_server
|
||||
echo ""
|
||||
check_website_server
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 [aliyun|website|all]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,76 +0,0 @@
|
||||
# 重大事件记录
|
||||
|
||||
**创建时间**: 2026-01-29 11:50:00 CST
|
||||
**父技能**: ops-tools
|
||||
|
||||
---
|
||||
|
||||
## 2026-01-17: Melbourne 服务器 VNC 配置失误导致系统崩溃
|
||||
|
||||
**事件时间**: 2026-01-17 08:49:00 - 09:02:00+ ACDT
|
||||
|
||||
**事件**: 执行 `sudo pkill -9 -u coolbuy-dev` 导致 Melbourne 服务器崩溃失联
|
||||
|
||||
**后果**:
|
||||
- macOS 图形系统崩溃
|
||||
- Tailscale VPN 中断
|
||||
- SSH 完全无法连接
|
||||
|
||||
**根本原因**: macOS 图形系统依赖用户会话,强制终止会导致 WindowServer 崩溃
|
||||
|
||||
**教训**:
|
||||
```bash
|
||||
# 永远不要在远程 macOS 上执行
|
||||
sudo pkill -9 -u <username>
|
||||
sudo killall -9 -u <username>
|
||||
```
|
||||
|
||||
**解决方案**: 需要物理访问恢复
|
||||
|
||||
---
|
||||
|
||||
## 2026-01-16: AI-Proj Webhook 自动部署重新启用
|
||||
|
||||
**事件时间**: 2026-01-16 11:06:01 CST
|
||||
|
||||
**事件**: Gitea webhook 重新启用,恢复 main 分支自动部署
|
||||
|
||||
**验证结果**:
|
||||
- Jenkins build #64 自动触发成功
|
||||
- 数据库数据完整保留(664条需求记录验证通过)
|
||||
- External volumes 配置有效
|
||||
|
||||
**部署流程**: `开发者 merge PR → Gitea webhook → Jenkins → 生产自动部署`
|
||||
|
||||
---
|
||||
|
||||
## 2026-01-15: AI-Proj 生产数据库丢失与恢复
|
||||
|
||||
**事件时间**: 2026-01-15 00:00:00 - 00:46:00 CST
|
||||
|
||||
**事件**: Jenkins 部署时 `docker compose down` 删除了非 external volumes
|
||||
|
||||
**影响**: 生产数据库完全清空,所有用户无法登录
|
||||
|
||||
**恢复过程**:
|
||||
1. 从本地开发环境恢复完整数据(41 用户、54 项目、4,722 任务)
|
||||
2. 使用新加坡跳板机优化传输
|
||||
3. 完全重建数据库
|
||||
|
||||
**恢复完成**: 2026-01-15 00:46:00 CST
|
||||
|
||||
**预防措施**:
|
||||
1. 所有数据卷标记为 `external: true`
|
||||
2. Jenkinsfile 添加自动数据库迁移
|
||||
3. 配置自动备份策略(本地 + 阿里云 OSS)
|
||||
|
||||
---
|
||||
|
||||
## 事件记录规范
|
||||
|
||||
记录重大事件时必须包含:
|
||||
- **事件时间**: 完整的开始和结束时间
|
||||
- **事件描述**: 清晰简洁的事件说明
|
||||
- **影响范围**: 受影响的系统和用户
|
||||
- **恢复过程**: 详细的恢复步骤
|
||||
- **预防措施**: 包含完成时间
|
||||
@@ -1,46 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Jenkins 构建触发脚本
|
||||
# 用法: ./jenkins-build.sh [job-name] [env]
|
||||
# 示例: ./jenkins-build.sh ai-proj staging
|
||||
|
||||
set -e
|
||||
|
||||
# 加载凭据
|
||||
source ~/.config/devops/credentials.env
|
||||
|
||||
JOB_NAME="${1:-ai-proj}"
|
||||
DEPLOY_ENV="${2:-staging}"
|
||||
|
||||
echo "触发 Jenkins 构建..."
|
||||
echo "Job: $JOB_NAME"
|
||||
echo "环境: $DEPLOY_ENV"
|
||||
echo ""
|
||||
|
||||
# 触发构建
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
"$JENKINS_URL/job/$JOB_NAME/buildWithParameters" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" \
|
||||
--data "DEPLOY_ENV=$DEPLOY_ENV&SKIP_TESTS=false")
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
|
||||
|
||||
if [ "$HTTP_CODE" = "201" ]; then
|
||||
echo "构建已触发成功!"
|
||||
echo ""
|
||||
echo "查看构建状态: $JENKINS_URL/job/$JOB_NAME/"
|
||||
|
||||
# 等待 2 秒后获取构建号
|
||||
sleep 2
|
||||
BUILD_INFO=$(curl -s "$JENKINS_URL/job/$JOB_NAME/lastBuild/api/json" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" 2>/dev/null)
|
||||
|
||||
if [ -n "$BUILD_INFO" ]; then
|
||||
BUILD_NUM=$(echo "$BUILD_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin).get('number','N/A'))" 2>/dev/null || echo "N/A")
|
||||
BUILD_STATUS=$(echo "$BUILD_INFO" | python3 -c "import sys,json; d=json.load(sys.stdin); print('进行中' if d.get('building') else d.get('result','未知'))" 2>/dev/null || echo "未知")
|
||||
echo "构建号: #$BUILD_NUM"
|
||||
echo "状态: $BUILD_STATUS"
|
||||
fi
|
||||
else
|
||||
echo "构建触发失败! HTTP 状态码: $HTTP_CODE"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,165 +0,0 @@
|
||||
# Claude Code MCP 配置指南
|
||||
|
||||
**创建时间**: 2026-01-29 11:50:00 CST
|
||||
**父技能**: ops-tools
|
||||
|
||||
## 概述
|
||||
|
||||
MCP (Model Context Protocol) 是 Claude Code 与外部服务集成的标准协议。
|
||||
|
||||
## 配置文件位置
|
||||
|
||||
| 配置文件 | 作用域 | 说明 |
|
||||
|----------|--------|------|
|
||||
| `~/.claude/.mcp.json` | 用户级(推荐) | 所有项目共享 |
|
||||
| `.claude/mcp.json` | 项目级 | 仅当前项目生效 |
|
||||
|
||||
## 配置模板(stdio 模式)
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"<服务名称>": {
|
||||
"type": "stdio",
|
||||
"command": "node",
|
||||
"args": ["<服务入口文件路径>"],
|
||||
"env": {
|
||||
"API_BASE": "<API基础URL>",
|
||||
"API_TOKEN": "<PAT令牌>",
|
||||
"NODE_ENV": "production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**参数说明**:
|
||||
|
||||
| 参数 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| `type` | 传输类型,固定为 `stdio` | `stdio` |
|
||||
| `command` | 启动命令 | `node` |
|
||||
| `args` | 入口文件路径 | `["dist/index.js"]` |
|
||||
| `env` | 环境变量 | API 地址、PAT 令牌 |
|
||||
|
||||
## ai-proj MCP 配置
|
||||
|
||||
**配置文件** (`~/.claude/.mcp.json`):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ai-proj": {
|
||||
"type": "stdio",
|
||||
"command": "node",
|
||||
"args": ["/Users/coolbuy-dev/coding/new-ai-proj/mcp-task-bridge/dist/index.js"],
|
||||
"env": {
|
||||
"TASK_API_BASE": "https://ai.pipexerp.com/api/v1",
|
||||
"TASK_API_TOKEN": "aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099",
|
||||
"NODE_ENV": "production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 环境变量
|
||||
|
||||
| 变量 | 说明 |
|
||||
|------|------|
|
||||
| `TASK_API_BASE` | `https://ai.pipexerp.com/api/v1` |
|
||||
| `TASK_API_TOKEN` | `aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099` |
|
||||
|
||||
### 前置条件
|
||||
|
||||
```bash
|
||||
# 编译 mcp-task-bridge
|
||||
cd /Users/coolbuy-dev/coding/new-ai-proj/mcp-task-bridge
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 验证步骤
|
||||
|
||||
```bash
|
||||
# 1. 手动测试服务
|
||||
cd /Users/coolbuy-dev/coding/new-ai-proj/mcp-task-bridge
|
||||
TASK_API_BASE="https://ai.pipexerp.com/api/v1" \
|
||||
TASK_API_TOKEN="aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099" \
|
||||
node dist/index.js
|
||||
|
||||
# 2. 测试 API 连接
|
||||
curl -s "https://ai.pipexerp.com/api/v1/projects" \
|
||||
-H "Authorization: Bearer aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099" | head -c 200
|
||||
|
||||
# 3. Claude Code 重连
|
||||
/mcp
|
||||
```
|
||||
|
||||
## 开发新 MCP 服务
|
||||
|
||||
### 步骤 1: 创建项目
|
||||
|
||||
```bash
|
||||
mkdir my-mcp-service && cd my-mcp-service
|
||||
npm init -y
|
||||
npm install @modelcontextprotocol/sdk
|
||||
```
|
||||
|
||||
### 步骤 2: 实现服务
|
||||
|
||||
```typescript
|
||||
// src/index.ts
|
||||
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||
|
||||
const server = new Server({
|
||||
name: "my-mcp-service",
|
||||
version: "1.0.0",
|
||||
}, { capabilities: { tools: {} } });
|
||||
|
||||
// 注册和实现工具...
|
||||
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
```
|
||||
|
||||
### 步骤 3: 编译和配置
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
vim ~/.claude/.mcp.json # 添加配置
|
||||
claude # 重启 Claude Code
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### MCP 连接失败
|
||||
|
||||
```bash
|
||||
# 1. 检查配置文件
|
||||
cat ~/.claude/.mcp.json | jq .
|
||||
|
||||
# 2. 检查服务文件
|
||||
ls -la <服务路径>/dist/index.js
|
||||
|
||||
# 3. 手动运行服务
|
||||
<环境变量> node dist/index.js
|
||||
```
|
||||
|
||||
**常见原因**:
|
||||
- 服务未编译 → `npm run build`
|
||||
- Token 无效 → 重新生成 PAT
|
||||
- `/mcp` 无效 → 重启 Claude Code
|
||||
|
||||
### 认证失败 (401)
|
||||
|
||||
```bash
|
||||
curl -s "<API_BASE>/auth/me" -H "Authorization: Bearer <TOKEN>"
|
||||
```
|
||||
|
||||
## 相关文件
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `~/.claude/.mcp.json` | MCP 配置 |
|
||||
| `mcp-task-bridge/dist/index.js` | ai-proj MCP 服务 |
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 部署状态检查脚本
|
||||
# 用法: ./deploy-check.sh [ai-proj|pipeXerp]
|
||||
|
||||
set -e
|
||||
|
||||
TOOLS_SERVER="root@101.200.136.200"
|
||||
TOOLS_KEY="~/.ssh/tools.pem"
|
||||
JOB_NAME="${1:-ai-proj}"
|
||||
|
||||
echo "======================================"
|
||||
echo "Jenkins Job: $JOB_NAME"
|
||||
echo "======================================"
|
||||
|
||||
ssh -i $TOOLS_KEY -o ConnectTimeout=5 $TOOLS_SERVER << EOF
|
||||
echo "--- 最近 5 次构建 ---"
|
||||
ls -lt /var/lib/jenkins/jobs/$JOB_NAME/builds/ 2>/dev/null | head -6
|
||||
|
||||
echo ""
|
||||
echo "--- 最近成功构建 ---"
|
||||
if [ -L /var/lib/jenkins/jobs/$JOB_NAME/builds/lastSuccessfulBuild ]; then
|
||||
BUILD_NUM=\$(readlink /var/lib/jenkins/jobs/$JOB_NAME/builds/lastSuccessfulBuild)
|
||||
echo "Build #\$BUILD_NUM"
|
||||
if [ -f "/var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log" ]; then
|
||||
echo "构建时间: \$(stat -c %y /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log 2>/dev/null || stat -f %Sm /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log)"
|
||||
fi
|
||||
else
|
||||
echo "无成功构建记录"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "--- 最近失败构建 ---"
|
||||
if [ -L /var/lib/jenkins/jobs/$JOB_NAME/builds/lastFailedBuild ]; then
|
||||
BUILD_NUM=\$(readlink /var/lib/jenkins/jobs/$JOB_NAME/builds/lastFailedBuild)
|
||||
echo "Build #\$BUILD_NUM"
|
||||
echo "错误日志(最后 20 行):"
|
||||
tail -20 /var/lib/jenkins/jobs/$JOB_NAME/builds/\$BUILD_NUM/log 2>/dev/null || echo "无法读取日志"
|
||||
else
|
||||
echo "无失败构建记录"
|
||||
fi
|
||||
EOF
|
||||
@@ -1,97 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Gitea PR 操作脚本
|
||||
# 用法:
|
||||
# ./gitea-pr.sh list # 列出 PR
|
||||
# ./gitea-pr.sh create <title> <head> # 创建 PR
|
||||
# ./gitea-pr.sh merge <pr-number> # 合并 PR
|
||||
|
||||
set -e
|
||||
|
||||
# 加载凭据
|
||||
source ~/.config/devops/credentials.env
|
||||
|
||||
REPO="Tools/new-ai-proj"
|
||||
ACTION="${1:-list}"
|
||||
|
||||
case "$ACTION" in
|
||||
list)
|
||||
echo "=== 当前 Pull Requests ==="
|
||||
curl -s "$GITEA_URL/api/v1/repos/$REPO/pulls?state=open" \
|
||||
-H "Authorization: token $GITEA_TOKEN" | \
|
||||
python3 -c "
|
||||
import sys, json
|
||||
prs = json.load(sys.stdin)
|
||||
if not prs:
|
||||
print('没有开放的 PR')
|
||||
else:
|
||||
for pr in prs:
|
||||
print(f\"#{pr['number']} [{pr['state']}] {pr['title']}\")
|
||||
print(f\" {pr['head']['ref']} -> {pr['base']['ref']}\")
|
||||
print(f\" 作者: {pr['user']['login']}\")
|
||||
print()
|
||||
"
|
||||
;;
|
||||
|
||||
create)
|
||||
TITLE="$2"
|
||||
HEAD="$3"
|
||||
BASE="${4:-main}"
|
||||
|
||||
if [ -z "$TITLE" ] || [ -z "$HEAD" ]; then
|
||||
echo "用法: $0 create <title> <head-branch> [base-branch]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "创建 PR: $TITLE"
|
||||
echo "分支: $HEAD -> $BASE"
|
||||
|
||||
curl -s -X POST "$GITEA_URL/api/v1/repos/$REPO/pulls" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"title\":\"$TITLE\",\"head\":\"$HEAD\",\"base\":\"$BASE\"}" | \
|
||||
python3 -c "
|
||||
import sys, json
|
||||
pr = json.load(sys.stdin)
|
||||
if 'number' in pr:
|
||||
print(f\"PR 创建成功! #{pr['number']}\")
|
||||
print(f\"URL: {pr['html_url']}\")
|
||||
else:
|
||||
print(f\"创建失败: {pr.get('message', '未知错误')}\")
|
||||
"
|
||||
;;
|
||||
|
||||
merge)
|
||||
PR_NUM="$2"
|
||||
|
||||
if [ -z "$PR_NUM" ]; then
|
||||
echo "用法: $0 merge <pr-number>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "合并 PR #$PR_NUM..."
|
||||
|
||||
curl -s -X POST "$GITEA_URL/api/v1/repos/$REPO/pulls/$PR_NUM/merge" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"Do":"merge"}' | \
|
||||
python3 -c "
|
||||
import sys, json
|
||||
try:
|
||||
result = json.load(sys.stdin)
|
||||
if result:
|
||||
print(f\"结果: {result}\")
|
||||
else:
|
||||
print('PR 合并成功!')
|
||||
except:
|
||||
print('PR 合并成功!')
|
||||
"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "用法: $0 {list|create|merge}"
|
||||
echo " list - 列出所有开放的 PR"
|
||||
echo " create <title> <head> - 创建新 PR"
|
||||
echo " merge <pr-number> - 合并 PR"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,84 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 服务器健康检查脚本
|
||||
# 用法: ./health-check.sh [aliyun|website|all]
|
||||
|
||||
set -e
|
||||
|
||||
TOOLS_SERVER="root@101.200.136.200"
|
||||
TOOLS_KEY="~/.ssh/tools.pem"
|
||||
WEBSITE_SERVER="root@192.144.137.14"
|
||||
WEBSITE_KEY="~/.ssh/officialWebsite.pem"
|
||||
|
||||
check_tools_server() {
|
||||
echo "======================================"
|
||||
echo "Tools 服务器 (101.200.136.200)"
|
||||
echo "======================================"
|
||||
|
||||
ssh -i $TOOLS_KEY -o ConnectTimeout=5 $TOOLS_SERVER << 'EOF'
|
||||
echo "--- 系统负载 ---"
|
||||
uptime
|
||||
|
||||
echo ""
|
||||
echo "--- 内存使用 ---"
|
||||
free -h
|
||||
|
||||
echo ""
|
||||
echo "--- 磁盘使用 ---"
|
||||
df -h | grep -E '^/dev|Filesystem'
|
||||
|
||||
echo ""
|
||||
echo "--- Docker 容器 ---"
|
||||
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
|
||||
|
||||
echo ""
|
||||
echo "--- 系统服务 ---"
|
||||
echo -n "Jenkins: "; systemctl is-active jenkins
|
||||
echo -n "Nginx: "; systemctl is-active nginx
|
||||
echo -n "Docker: "; systemctl is-active docker
|
||||
|
||||
echo ""
|
||||
echo "--- 端口检查 ---"
|
||||
netstat -tlnp 2>/dev/null | grep -E ':3000|:8080|:10022|:5000' | awk '{print $4, $7}'
|
||||
EOF
|
||||
}
|
||||
|
||||
check_website_server() {
|
||||
echo "======================================"
|
||||
echo "Website 服务器 (192.144.137.14)"
|
||||
echo "======================================"
|
||||
|
||||
ssh -i $WEBSITE_KEY -o ConnectTimeout=5 $WEBSITE_SERVER << 'EOF'
|
||||
echo "--- 系统负载 ---"
|
||||
uptime
|
||||
|
||||
echo ""
|
||||
echo "--- 内存使用 ---"
|
||||
free -h
|
||||
|
||||
echo ""
|
||||
echo "--- 磁盘使用 ---"
|
||||
df -h | grep -E '^/dev|Filesystem'
|
||||
|
||||
echo ""
|
||||
echo "--- Nginx 状态 ---"
|
||||
systemctl is-active nginx || echo "nginx not running"
|
||||
EOF
|
||||
}
|
||||
|
||||
case "${1:-all}" in
|
||||
aliyun|tools)
|
||||
check_tools_server
|
||||
;;
|
||||
website)
|
||||
check_website_server
|
||||
;;
|
||||
all)
|
||||
check_tools_server
|
||||
echo ""
|
||||
check_website_server
|
||||
;;
|
||||
*)
|
||||
echo "用法: $0 [aliyun|website|all]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -1,46 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Jenkins 构建触发脚本
|
||||
# 用法: ./jenkins-build.sh [job-name] [env]
|
||||
# 示例: ./jenkins-build.sh ai-proj staging
|
||||
|
||||
set -e
|
||||
|
||||
# 加载凭据
|
||||
source ~/.config/devops/credentials.env
|
||||
|
||||
JOB_NAME="${1:-ai-proj}"
|
||||
DEPLOY_ENV="${2:-staging}"
|
||||
|
||||
echo "触发 Jenkins 构建..."
|
||||
echo "Job: $JOB_NAME"
|
||||
echo "环境: $DEPLOY_ENV"
|
||||
echo ""
|
||||
|
||||
# 触发构建
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
|
||||
"$JENKINS_URL/job/$JOB_NAME/buildWithParameters" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" \
|
||||
--data "DEPLOY_ENV=$DEPLOY_ENV&SKIP_TESTS=false")
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
|
||||
|
||||
if [ "$HTTP_CODE" = "201" ]; then
|
||||
echo "构建已触发成功!"
|
||||
echo ""
|
||||
echo "查看构建状态: $JENKINS_URL/job/$JOB_NAME/"
|
||||
|
||||
# 等待 2 秒后获取构建号
|
||||
sleep 2
|
||||
BUILD_INFO=$(curl -s "$JENKINS_URL/job/$JOB_NAME/lastBuild/api/json" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" 2>/dev/null)
|
||||
|
||||
if [ -n "$BUILD_INFO" ]; then
|
||||
BUILD_NUM=$(echo "$BUILD_INFO" | python3 -c "import sys,json; print(json.load(sys.stdin).get('number','N/A'))" 2>/dev/null || echo "N/A")
|
||||
BUILD_STATUS=$(echo "$BUILD_INFO" | python3 -c "import sys,json; d=json.load(sys.stdin); print('进行中' if d.get('building') else d.get('result','未知'))" 2>/dev/null || echo "未知")
|
||||
echo "构建号: #$BUILD_NUM"
|
||||
echo "状态: $BUILD_STATUS"
|
||||
fi
|
||||
else
|
||||
echo "构建触发失败! HTTP 状态码: $HTTP_CODE"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 服务重启脚本
|
||||
# 用法: ./service-restart.sh <service-name>
|
||||
# 支持: gitea, jenkins, nginx, registry
|
||||
|
||||
set -e
|
||||
|
||||
TOOLS_SERVER="root@101.200.136.200"
|
||||
TOOLS_KEY="~/.ssh/tools.pem"
|
||||
SERVICE_NAME="$1"
|
||||
|
||||
if [ -z "$SERVICE_NAME" ]; then
|
||||
echo "用法: $0 <service-name>"
|
||||
echo "支持的服务: gitea, jenkins, nginx, registry, docker"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "正在重启服务: $SERVICE_NAME ..."
|
||||
|
||||
case "$SERVICE_NAME" in
|
||||
gitea)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "docker restart gitea && docker logs --tail 10 gitea"
|
||||
;;
|
||||
registry)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "docker restart registry && docker ps | grep registry"
|
||||
;;
|
||||
jenkins)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "systemctl restart jenkins && systemctl status jenkins --no-pager"
|
||||
;;
|
||||
nginx)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "nginx -t && systemctl restart nginx && systemctl status nginx --no-pager"
|
||||
;;
|
||||
docker)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "systemctl restart docker && docker ps"
|
||||
;;
|
||||
*)
|
||||
echo "不支持的服务: $SERVICE_NAME"
|
||||
echo "支持的服务: gitea, jenkins, nginx, registry, docker"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "服务 $SERVICE_NAME 重启完成"
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 服务重启脚本
|
||||
# 用法: ./service-restart.sh <service-name>
|
||||
# 支持: gitea, jenkins, nginx, registry
|
||||
|
||||
set -e
|
||||
|
||||
TOOLS_SERVER="root@101.200.136.200"
|
||||
TOOLS_KEY="~/.ssh/tools.pem"
|
||||
SERVICE_NAME="$1"
|
||||
|
||||
if [ -z "$SERVICE_NAME" ]; then
|
||||
echo "用法: $0 <service-name>"
|
||||
echo "支持的服务: gitea, jenkins, nginx, registry, docker"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "正在重启服务: $SERVICE_NAME ..."
|
||||
|
||||
case "$SERVICE_NAME" in
|
||||
gitea)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "docker restart gitea && docker logs --tail 10 gitea"
|
||||
;;
|
||||
registry)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "docker restart registry && docker ps | grep registry"
|
||||
;;
|
||||
jenkins)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "systemctl restart jenkins && systemctl status jenkins --no-pager"
|
||||
;;
|
||||
nginx)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "nginx -t && systemctl restart nginx && systemctl status nginx --no-pager"
|
||||
;;
|
||||
docker)
|
||||
ssh -i $TOOLS_KEY $TOOLS_SERVER "systemctl restart docker && docker ps"
|
||||
;;
|
||||
*)
|
||||
echo "不支持的服务: $SERVICE_NAME"
|
||||
echo "支持的服务: gitea, jenkins, nginx, registry, docker"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "服务 $SERVICE_NAME 重启完成"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "coolbuy-legacy-plugin",
|
||||
"description": "酷采2.0团购管理系统测试与维护。用于酷采2.0系统的功能测试、问题排查、需求验证和对比测试。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,414 +0,0 @@
|
||||
---
|
||||
name: coolbuy-legacy
|
||||
description: 酷采2.0团购管理系统测试与维护。用于酷采2.0系统的功能测试、问题排查、需求验证和对比测试。当用户提到酷采2.0、百丽、李宁、遗留系统测试相关任务时自动激活。
|
||||
---
|
||||
|
||||
# Coolbuy Legacy (酷采2.0) Skill
|
||||
|
||||
酷采2.0团购管理系统,服务于百丽、李宁等客户的遗留系统,采用 Vue 2 + Element UI + Java Spring 技术栈。
|
||||
|
||||
## 项目信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 项目编号 | P264 |
|
||||
| 项目名称 | 酷采 2.0 |
|
||||
| AI-Proj 项目ID | 164 |
|
||||
| 源码路径 | `/Users/donglinlai/workspace/coolbuy-legacy` |
|
||||
| Git 仓库 | `git@gitea.pipexerp.com:pipexerp/coolbuy-legacy.git` |
|
||||
| 主分支 | main |
|
||||
| 技术栈 | Vue 2 + Element UI + Java Spring |
|
||||
|
||||
---
|
||||
|
||||
## 系统访问
|
||||
|
||||
### 测试环境
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 测试地址 | http://47.105.185.154:9300/login |
|
||||
| 管理员账号 | 19090009801 |
|
||||
| 密码 | 123456 |
|
||||
| 客户账号 | 17761202551 / 202551 |
|
||||
| 服务器 | 47.105.185.154 |
|
||||
|
||||
### 主要客户
|
||||
|
||||
- **百丽集团** - 大型鞋业零售集团
|
||||
- **李宁体育** - 知名体育用品品牌
|
||||
|
||||
---
|
||||
|
||||
## 架构概览
|
||||
|
||||
```
|
||||
coolbuy-legacy/
|
||||
├── cool_lining/module-provider/ # Java 后端服务
|
||||
│ └── src/main/java/com/jzg/module/
|
||||
│ ├── action/ # 控制器层
|
||||
│ │ ├── prd/ # 商品模块控制器
|
||||
│ │ ├── order/ # 订单模块控制器
|
||||
│ │ └── customer/ # 客户模块控制器
|
||||
│ ├── dao/model/ # 数据模型
|
||||
│ │ ├── prd/ # 商品实体
|
||||
│ │ ├── order/ # 订单实体
|
||||
│ │ └── customer/ # 客户实体
|
||||
│ └── manager/ # 业务逻辑层
|
||||
│ ├── prd/ # 商品业务逻辑
|
||||
│ ├── order/ # 订单业务逻辑
|
||||
│ └── customer/ # 客户业务逻辑
|
||||
└── ln_admin/ # Vue 2 前端
|
||||
└── src/views2/module/ # 业务模块页面
|
||||
├── prd/ # 商品管理页面
|
||||
├── order/ # 订单管理页面
|
||||
└── customer/ # 客户管理页面
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 主要功能模块
|
||||
|
||||
### 核心业务模块
|
||||
|
||||
1. **推广方案管理**
|
||||
- 促销活动配置
|
||||
- 折扣规则设置
|
||||
- 活动效果统计
|
||||
|
||||
2. **销售管理**
|
||||
- 订单处理流程
|
||||
- 销售数据统计
|
||||
- 客户下单管理
|
||||
|
||||
3. **草稿单管理**
|
||||
- 未完成订单保存
|
||||
- 草稿单编辑
|
||||
- 批量转正式单
|
||||
|
||||
4. **Y码直客**
|
||||
- 直客订单管理
|
||||
- Y码生成与核销
|
||||
- 直客价格体系
|
||||
|
||||
5. **库存管理**
|
||||
- 库存查询
|
||||
- 库存调拨
|
||||
- 库存预警
|
||||
|
||||
6. **货盘管理**
|
||||
- 货盘创建
|
||||
- 货盘分配
|
||||
- 货盘跟踪
|
||||
|
||||
7. **协同仓管理**
|
||||
- 多仓协同
|
||||
- 仓库调度
|
||||
- 发货管理
|
||||
|
||||
8. **价格管理**
|
||||
- 商品定价
|
||||
- 客户价格体系
|
||||
- 最低折扣限制
|
||||
|
||||
9. **资金管理**
|
||||
- 账户余额
|
||||
- 充值记录
|
||||
- 消费明细
|
||||
|
||||
10. **产品管理** ⭐
|
||||
- 商品信息维护
|
||||
- SPU/SKU管理
|
||||
- 商品分类
|
||||
|
||||
11. **基础功能**
|
||||
- 客户管理
|
||||
- 用户权限
|
||||
- 系统配置
|
||||
|
||||
12. **数据看板**
|
||||
- 销售数据分析
|
||||
- 库存报表
|
||||
- 业务概览
|
||||
|
||||
13. **公告通知**
|
||||
- 系统公告
|
||||
- 消息推送
|
||||
- 通知管理
|
||||
|
||||
14. **起售数量设置**
|
||||
- 最小起售量
|
||||
- 批量设置
|
||||
- 规则配置
|
||||
|
||||
---
|
||||
|
||||
## 与酷采3.0的对比
|
||||
|
||||
### 技术栈差异
|
||||
|
||||
| 项目 | 酷采2.0 (Legacy) | 酷采3.0 (PaaS) |
|
||||
|------|------------------|----------------|
|
||||
| 前端框架 | Vue 2 | React 18 |
|
||||
| UI组件库 | Element UI | Ant Design |
|
||||
| 前端构建 | Webpack | Vite |
|
||||
| 后端语言 | Java | Go |
|
||||
| 后端框架 | Spring Boot | Gin + go-zero |
|
||||
| 数据库 | MySQL | PostgreSQL |
|
||||
| 架构模式 | 单体应用 | 微服务 |
|
||||
| 部署方式 | 传统部署 | Docker + K8s |
|
||||
|
||||
### 业务差异
|
||||
|
||||
| 功能 | 酷采2.0 | 酷采3.0 |
|
||||
|------|---------|---------|
|
||||
| 多租户 | ❌ 单租户 | ✅ 多租户 SaaS |
|
||||
| 客户隔离 | 账号级别 | 企业级别 |
|
||||
| 定制化 | 客户专属部署 | 配置化租户 |
|
||||
| 扩展性 | 垂直扩展 | 水平扩展 |
|
||||
|
||||
---
|
||||
|
||||
## 测试任务管理
|
||||
|
||||
### AI-Proj 项目集成
|
||||
|
||||
当前项目在 AI-Proj 系统中的ID为 **164**,包含以下测试任务:
|
||||
|
||||
#### 客户最低折扣申请限制功能测试
|
||||
|
||||
**父任务**: #4725 (in_progress)
|
||||
|
||||
**测试用例**:
|
||||
- ✅ TC001: 按客户类型配置最低折扣 [P0] - #4726
|
||||
- ✅ TC002: 按特定客户配置最低折扣 [P0] - #4727
|
||||
- ✅ TC003: 折扣下限输入验证 [P1] - #4728
|
||||
- ✅ TC004: 阈值导入模板 [P1] - #4729
|
||||
- ✅ TC005: 折扣低于下限 - 拦截 [P0] - #4730
|
||||
- ✅ TC006: 折扣等于下限 - 通过 [P0] - #4731
|
||||
- ✅ TC007: 折扣高于下限 - 通过 [P1] - #4732
|
||||
- 🔄 TC008: 多商品触发限制 - 罗列提示 [P0] - #4733
|
||||
- ⏳ TC009: 非一级账号不受限 [P1] - #4734
|
||||
- ⏳ TC010: 审核修改折扣低于下限 - 拦截 [P0] - #4735
|
||||
- ⏳ TC011: 审核修改折扣等于下限 - 通过 [P0] - #4736
|
||||
- ⏳ TC012: 限价标签显示 [P1] - #4737
|
||||
- ⏳ TC013: 提示文字验证 [P1] - #4738
|
||||
|
||||
### 查询任务
|
||||
|
||||
```javascript
|
||||
// 获取酷采2.0项目任务列表
|
||||
mcp__ai-proj__list_tasks({ projectId: 164 })
|
||||
|
||||
// 获取特定任务详情
|
||||
mcp__ai-proj__get_detailed_task_info({ taskId: 4725 })
|
||||
|
||||
// 获取任务文档
|
||||
mcp__ai-proj__get_task_document({ taskId: 4725 })
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chrome DevTools 浏览器自动化
|
||||
|
||||
### 启动调试模式
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
||||
--remote-debugging-port=9222 \
|
||||
--user-data-dir=/tmp/chrome-debug
|
||||
```
|
||||
|
||||
### 验证连接
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:9222/json/version
|
||||
```
|
||||
|
||||
### 验证码处理规则
|
||||
|
||||
**重要**: 当访问需要验证码的系统时:
|
||||
|
||||
1. **不要**使用脚本截图方式获取验证码(验证码会快速过期)
|
||||
2. **直接提醒用户**:
|
||||
- 请在浏览器中输入验证码
|
||||
- 或请帮我点击登录按钮
|
||||
3. 用户操作完成后再继续自动化流程
|
||||
|
||||
示例提示:
|
||||
```
|
||||
浏览器已打开登录页面,验证码需要手动输入。请在 Chrome 浏览器中:
|
||||
1. 输入验证码
|
||||
2. 点击登录按钮
|
||||
完成后告诉我,我将继续后续操作。
|
||||
```
|
||||
|
||||
### 常用 MCP 操作
|
||||
|
||||
```javascript
|
||||
// 列出所有页面
|
||||
mcp__chrome-devtools__list_pages()
|
||||
|
||||
// 选择页面
|
||||
mcp__chrome-devtools__select_page({ pageId: 1 })
|
||||
|
||||
// 导航到URL
|
||||
mcp__chrome-devtools__navigate_page({
|
||||
type: "url",
|
||||
url: "http://47.105.185.154:9300/login"
|
||||
})
|
||||
|
||||
// 截图
|
||||
mcp__chrome-devtools__take_screenshot({
|
||||
format: "png",
|
||||
filePath: "/tmp/screenshot.png"
|
||||
})
|
||||
|
||||
// 获取页面快照
|
||||
mcp__chrome-devtools__take_snapshot()
|
||||
|
||||
// 点击元素
|
||||
mcp__chrome-devtools__click({ uid: "element_uid" })
|
||||
|
||||
// 填写表单
|
||||
mcp__chrome-devtools__fill({
|
||||
uid: "input_uid",
|
||||
value: "text"
|
||||
})
|
||||
|
||||
// 执行JavaScript
|
||||
mcp__chrome-devtools__evaluate_script({
|
||||
function: "() => { return document.title; }"
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见测试场景
|
||||
|
||||
### 1. 客户最低折扣测试
|
||||
|
||||
**测试步骤**:
|
||||
1. 登录管理员账号 (19090009801)
|
||||
2. 进入价格管理 → 最低折扣配置
|
||||
3. 配置客户类型或特定客户的最低折扣
|
||||
4. 使用客户账号 (17761202551) 登录
|
||||
5. 创建订单,测试折扣限制规则
|
||||
|
||||
**验证点**:
|
||||
- 折扣低于下限时系统拦截
|
||||
- 折扣等于或高于下限时通过
|
||||
- 多商品触发时正确罗列提示
|
||||
- 非一级账号不受限制
|
||||
|
||||
### 2. 订单流程测试
|
||||
|
||||
**测试步骤**:
|
||||
1. 客户账号登录
|
||||
2. 选择商品加入购物车
|
||||
3. 提交订单
|
||||
4. 审核订单 (管理员)
|
||||
5. 发货处理
|
||||
6. 订单完成
|
||||
|
||||
### 3. 库存管理测试
|
||||
|
||||
**测试步骤**:
|
||||
1. 查询库存
|
||||
2. 创建库存调拨单
|
||||
3. 审核调拨单
|
||||
4. 确认入库
|
||||
5. 验证库存变化
|
||||
|
||||
---
|
||||
|
||||
## 需求对比测试流程
|
||||
|
||||
当酷采3.0实现新功能时,需要与酷采2.0进行对比:
|
||||
|
||||
### 测试流程
|
||||
|
||||
1. **功能分析**
|
||||
- 在酷采2.0中找到对应功能
|
||||
- 记录现有实现方式
|
||||
- 识别差异点
|
||||
|
||||
2. **页面对比**
|
||||
- 截图酷采2.0界面
|
||||
- 对比UI/UX差异
|
||||
- 记录交互流程
|
||||
|
||||
3. **数据对比**
|
||||
- 对比数据模型
|
||||
- 验证业务规则
|
||||
- 确认边界条件
|
||||
|
||||
4. **性能对比**
|
||||
- 记录响应时间
|
||||
- 对比并发能力
|
||||
- 评估用户体验
|
||||
|
||||
---
|
||||
|
||||
## 问题排查
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **登录失败**
|
||||
- 检查账号密码是否正确
|
||||
- 验证码是否过期
|
||||
- 网络连接是否正常
|
||||
|
||||
2. **页面加载慢**
|
||||
- 检查网络状况
|
||||
- 清除浏览器缓存
|
||||
- 查看服务器日志
|
||||
|
||||
3. **数据不同步**
|
||||
- 刷新页面
|
||||
- 检查数据库连接
|
||||
- 查看后端日志
|
||||
|
||||
### 日志查看
|
||||
|
||||
```bash
|
||||
# SSH到测试服务器
|
||||
ssh root@47.105.185.154
|
||||
|
||||
# 查看应用日志
|
||||
tail -f /path/to/coolbuy/logs/application.log
|
||||
|
||||
# 查看错误日志
|
||||
tail -f /path/to/coolbuy/logs/error.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关技能
|
||||
|
||||
- `coolbuy-paas` - 酷采3.0 SaaS租户端开发
|
||||
- `coolbuy-platform` - 酷采3.0平台管理端
|
||||
- `dev-test` - 软件测试技能
|
||||
- `req` - 需求管理技能
|
||||
- `siyuan` - 思源笔记(含酷采相关文档)
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| 1.0.0 | 2026-01-21 | 初始版本,创建酷采2.0独立技能 |
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
⚠️ **重要提醒**:
|
||||
|
||||
1. 酷采2.0为遗留系统,主要用于参考和对比测试
|
||||
2. 新功能开发应在酷采3.0 (coolbuy-paas) 中进行
|
||||
3. 测试环境数据仅供测试使用,请勿在生产环境操作
|
||||
4. 百丽、李宁等客户仍在使用此系统,测试时注意不要影响生产数据
|
||||
5. 发现问题及时记录到 AI-Proj 系统中
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "coolbuy-paas-plugin",
|
||||
"description": "酷采3.0 SaaS 租户端开发与测试。用于商品管理、订单管理等业务模块开发,以及酷采2.0系统对比测试。",
|
||||
"version": "1.3.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,803 +0,0 @@
|
||||
---
|
||||
name: coolbuy-paas
|
||||
description: 酷采3.0 SaaS 租户端开发与测试。用于商品管理、订单管理等业务模块开发,以及酷采2.0系统对比测试。当用户提到酷采、coolbuy-paas、商品管理、产品管理、酷采2.0测试相关任务时自动激活。
|
||||
---
|
||||
|
||||
# Coolbuy PaaS Skill
|
||||
|
||||
酷采3.0 SaaS 多租户业务系统,采用 Go + React 技术栈。
|
||||
|
||||
## 项目信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本地路径 | `/Users/donglinlai/coding/qiudl/coolbuy-paas` |
|
||||
| 工作区路径 | `/Users/donglinlai/workspace/coolbuy-paas` |
|
||||
| Git 仓库 | `git@gitea.pipexerp.com:pipexerp/coolbuy-paas.git` |
|
||||
| 主分支 | main |
|
||||
| 技术栈 | Go (Gin+GORM) + React 18 (Vite+TypeScript+Ant Design) |
|
||||
|
||||
---
|
||||
|
||||
## 架构概览
|
||||
|
||||
```
|
||||
coolbuy-paas/
|
||||
├── erp-service/ # Go 后端 - ERP业务服务 (port 7091)
|
||||
│ ├── api/ # API 定义 (go-zero)
|
||||
│ ├── internal/
|
||||
│ │ ├── product/ # 商品模块
|
||||
│ │ ├── order/ # 订单模块
|
||||
│ │ └── inventory/ # 库存模块
|
||||
│ └── configs/
|
||||
├── foundation-service/ # 基础服务 (port 7090)
|
||||
├── auth-service/ # 认证服务 (port 7089)
|
||||
├── ai-service/ # AI 服务 (port 7092) - AI Chat, Tool Calling
|
||||
│ ├── api/
|
||||
│ │ └── etc/ # 配置文件 (多环境)
|
||||
│ └── services/
|
||||
│ ├── chat_service.go # 对话服务
|
||||
│ └── ai_ticket_reporter.go # AI 工单上报
|
||||
├── gateway/ # API 网关
|
||||
├── web/ # React 前端 - 租户端 (port 4000)
|
||||
│ ├── src/
|
||||
│ │ ├── services/ # API 服务
|
||||
│ │ │ ├── aiChatApi.ts
|
||||
│ │ │ └── chatSessionService.ts
|
||||
│ │ └── components/AIChat/ # AI 聊天组件
|
||||
│ └── .env.* # 环境配置
|
||||
└── web-mall/ # React 前端 - 独立商城 (port 5174)
|
||||
├── src/
|
||||
│ ├── pages/ # 首页/分类/商品/购物车/结算/个人中心
|
||||
│ ├── api/ # API 层(共享 erp-service)
|
||||
│ ├── auth/ # 认证(共享 auth-service JWT)
|
||||
│ ├── store/ # Zustand 状态管理
|
||||
│ └── layouts/ # 商城布局(顶部导航,非侧边栏)
|
||||
├── nginx.conf # 生产 Nginx 配置
|
||||
└── Dockerfile # 多阶段构建
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 多环境配置
|
||||
|
||||
### 运行环境
|
||||
|
||||
| 环境 | 前端配置 | 后端配置 | 说明 |
|
||||
|------|---------|---------|------|
|
||||
| development | `.env.development` | `ai-api.yaml` | 本地开发 |
|
||||
| staging | `.env.staging` | `ai-api.staging.yaml` | 预发布环境 |
|
||||
| production | `.env.production` | `ai-api.production.yaml` | 生产环境 |
|
||||
|
||||
### 核心环境变量
|
||||
|
||||
| 变量 | 说明 | 开发环境示例 |
|
||||
|------|------|------------|
|
||||
| `VITE_AUTH_SERVICE_URL` | 认证服务 | `http://127.0.0.1:7089` |
|
||||
| `VITE_FOUNDATION_SERVICE_URL` | 基础服务 | `http://127.0.0.1:7090` |
|
||||
| `VITE_BUSINESS_SERVICE_URL` | ERP服务 | `http://127.0.0.1:7091` |
|
||||
| `VITE_AI_SERVICE_URL` | AI服务 | `http://127.0.0.1:7092` |
|
||||
| `VITE_AI_PROJ_URL` | ai-proj服务 | `http://127.0.0.1:8080` |
|
||||
|
||||
### Vite 代理配置 (vite.config.ts)
|
||||
|
||||
```typescript
|
||||
proxy: {
|
||||
'/api/v1/auth': { target: VITE_AUTH_SERVICE_URL },
|
||||
'/api/v1/ai': { target: VITE_AI_SERVICE_URL }, // AI Chat
|
||||
'/api/v1/chat': { target: VITE_AI_PROJ_URL }, // Chat Sessions
|
||||
'/api/v1': { target: VITE_BUSINESS_SERVICE_URL }, // 默认路由
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AI 服务集成
|
||||
|
||||
### AI Chat 功能
|
||||
|
||||
| 端点 | 服务 | 说明 |
|
||||
|------|------|------|
|
||||
| `/api/v1/ai/chat/stream` | ai-service (7092) | 流式对话 |
|
||||
| `/api/v1/ai/tools` | ai-service (7092) | 获取可用工具 |
|
||||
| `/api/v1/chat/sessions` | ai-proj (8080) | 会话管理 |
|
||||
| `/api/v1/ai-tickets` | ai-proj (8080) | AI 工单 |
|
||||
|
||||
### AI Chat 代码路径(重要)
|
||||
|
||||
**前端实际调用链**:
|
||||
```
|
||||
useChat.ts
|
||||
→ import * as aiChatService from '@/services/aiChatApi' ← 实际使用的文件!
|
||||
→ aiChatApi.sendChatMessageStream()
|
||||
→ aiChatApi.sendStreamingChatRequest() ← 用 fetch() 直接发 SSE 请求
|
||||
```
|
||||
|
||||
**注意**:`@/services/aiChatService.ts` 是遗留文件,**未被使用**。修改 AI Chat 前端逻辑时必须修改 `aiChatApi.ts`。
|
||||
|
||||
**流式请求绕过 axios**:`aiChatApi.ts` 使用原生 `fetch()` 发送 SSE 请求,不经过 `request.ts` 的 axios 拦截器。因此 `Authorization`、`X-Tenant-ID` 等 header 需要在 `fetch()` 中手动添加。
|
||||
|
||||
### AI Chat 认证链路
|
||||
|
||||
```
|
||||
前端登录 → auth-service 返回 JWT (含 tenant_id, username, roles)
|
||||
→ localStorage 存储 user_info + token
|
||||
→ AI Chat 发送请求时:
|
||||
1. getToken() 获取 JWT
|
||||
2. getTenantIdFromContext() 获取 tenant_id
|
||||
3. fetch() 携带 Authorization + X-Tenant-ID header
|
||||
→ ai-service auth middleware 解析 JWT claims
|
||||
→ Go context 注入 user_id, username, tenant_id, tenant_code, roles
|
||||
→ buildUserIdentityContext(ctx) 提取并追加到 system prompt
|
||||
→ AI 能回答"我的租户ID是什么"等问题
|
||||
```
|
||||
|
||||
**关键文件**:
|
||||
| 文件 | 作用 |
|
||||
|------|------|
|
||||
| `web/src/services/aiChatApi.ts` | 前端 AI Chat API(实际使用) |
|
||||
| `web/src/hooks/useChat.ts` | Chat 状态管理 Hook |
|
||||
| `ai-service/api/internal/middleware/auth_middleware.go` | JWT 解析,注入 context |
|
||||
| `ai-service/services/chat_service.go` | 对话服务,system prompt 注入 |
|
||||
| `ai-service/services/context_builder.go` | 用户上下文构建 |
|
||||
|
||||
**JWT 密钥一致性**:auth-service 和 ai-service 的 `JWT.AccessSecret` 必须一致,否则 ai-service 无法验证 token(开发环境有 flexible parse 兜底)。
|
||||
|
||||
### AI 工单上报
|
||||
|
||||
ai-service 的错误会自动上报到 ai-proj 的 AI 工单系统:
|
||||
|
||||
```yaml
|
||||
# ai-service/api/etc/ai-api.yaml
|
||||
AITicketReporter:
|
||||
Enabled: true
|
||||
AiProjURL: "http://localhost:8080"
|
||||
```
|
||||
|
||||
错误类型自动分类:
|
||||
- `api_error` - API 调用错误
|
||||
- `missing_tool` - 工具调用错误
|
||||
- `timeout` - 超时错误
|
||||
- `permission_denied` - 权限错误
|
||||
|
||||
---
|
||||
|
||||
## 酷采2.0 测试环境 (Legacy)
|
||||
|
||||
用于参考和对比酷采3.0开发。
|
||||
|
||||
### 访问信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 测试地址 | http://47.105.185.154:9300/login |
|
||||
| 管理员账号 | 19090009801 |
|
||||
| 密码 | 123456 |
|
||||
| 客户账号 | 17761202551 / 202551 |
|
||||
| 技术栈 | Vue 2 + Element UI + Java Spring |
|
||||
|
||||
### 主要功能模块
|
||||
|
||||
- 推广方案、销售管理、草稿单管理
|
||||
- Y码直客、库存管理、货盘管理
|
||||
- 协同仓、价格管理、资金管理
|
||||
- 基础功能、数据看板、公告通知
|
||||
- 起售数量设置、**产品管理**
|
||||
|
||||
### 源码位置
|
||||
|
||||
```
|
||||
~/workspace/coolbuy-legacy/
|
||||
├── cool_lining/module-provider/ # Java 后端
|
||||
│ └── src/main/java/com/jzg/module/
|
||||
│ ├── action/prd/ # 商品控制器
|
||||
│ ├── dao/model/prd/ # 商品实体
|
||||
│ └── manager/prd/ # 商品业务逻辑
|
||||
└── ln_admin/ # Vue 前端
|
||||
└── src/views2/module/prd/ # 商品管理页面
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chrome DevTools 浏览器自动化
|
||||
|
||||
用于系统测试、截图、UI验证。
|
||||
|
||||
### 启动 Chrome 调试模式
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
||||
--remote-debugging-port=9222 \
|
||||
--user-data-dir=/tmp/chrome-debug
|
||||
```
|
||||
|
||||
### 验证连接
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:9222/json/version
|
||||
```
|
||||
|
||||
### 验证码处理规则
|
||||
|
||||
**重要**: 当访问需要验证码的系统时:
|
||||
|
||||
1. **不要**使用脚本截图方式获取验证码(验证码会快速过期)
|
||||
2. **直接提醒用户**:
|
||||
- 请在浏览器中输入验证码
|
||||
- 或请帮我点击登录按钮
|
||||
3. 用户操作完成后再继续自动化流程
|
||||
|
||||
示例提示:
|
||||
```
|
||||
浏览器已打开登录页面,验证码需要手动输入。请在 Chrome 浏览器中:
|
||||
1. 输入验证码
|
||||
2. 点击登录按钮
|
||||
完成后告诉我,我将继续后续操作。
|
||||
```
|
||||
|
||||
### 常用 CDP 操作
|
||||
|
||||
```javascript
|
||||
// 截图
|
||||
Page.captureScreenshot({ format: 'png' })
|
||||
|
||||
// 导航
|
||||
Page.navigate({ url: 'http://...' })
|
||||
|
||||
// 执行 JS
|
||||
Runtime.evaluate({ expression: '...' })
|
||||
|
||||
// 点击元素
|
||||
Runtime.evaluate({
|
||||
expression: `document.querySelector('button').click()`
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 酷采3.0 PRD 参考
|
||||
|
||||
PRD 文档存储在 ai-proj 任务系统:
|
||||
|
||||
| 模块 | 任务ID | 文档名称 |
|
||||
|------|--------|----------|
|
||||
| 商品管理 | #4754 | 酷采3.0商品管理模块 |
|
||||
| 商品基本信息 | #4770 | 商品基本信息管理模块PRD |
|
||||
|
||||
获取 PRD 文档:
|
||||
```
|
||||
mcp__ai-proj__get_task_document(taskId: 4770)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 本地开发
|
||||
|
||||
### 启动服务
|
||||
|
||||
```bash
|
||||
# ERP 服务 (port 7091)
|
||||
cd erp-service && go run api/main.go -f configs/config.local.yaml
|
||||
|
||||
# AI 服务 (port 7092)
|
||||
cd ai-service && go run api/ai.go -f api/etc/ai-api.yaml
|
||||
|
||||
# 租户端前端 (port 4000)
|
||||
cd web && npm run dev
|
||||
|
||||
# 独立商城前端 (port 5174)
|
||||
cd web-mall && npm run dev
|
||||
```
|
||||
|
||||
### 依赖服务
|
||||
|
||||
| 服务 | 端口 | 说明 |
|
||||
|------|------|------|
|
||||
| PostgreSQL | 5432 | 本地数据库 |
|
||||
| Redis | 6379 | 缓存 |
|
||||
| ai-proj | 8080 | AI 项目管理(可选,用于 Chat Sessions) |
|
||||
|
||||
### 本地数据库
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 类型 | PostgreSQL |
|
||||
| Database | paas_foundation |
|
||||
| User | coolbuy-dev |
|
||||
| Password | (空) |
|
||||
|
||||
### 远程数据库(生产参考)
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| Host | 192.144.137.14 |
|
||||
| Database | coolbuy_paas |
|
||||
| User | platform |
|
||||
| Password | Zhiyuncai2025~ |
|
||||
|
||||
### 数据库管理工具 - TablePlus
|
||||
|
||||
**推荐工具**: TablePlus - macOS 原生数据库 GUI 客户端,支持 PostgreSQL/MySQL/Redis 等。
|
||||
|
||||
#### 安装 TablePlus
|
||||
|
||||
```bash
|
||||
# 使用 Homebrew 安装
|
||||
brew install --cask tableplus
|
||||
|
||||
# 启动 TablePlus
|
||||
open -a TablePlus
|
||||
```
|
||||
|
||||
#### 自动配置数据库连接
|
||||
|
||||
TablePlus 的连接配置存储在 `~/Library/Application Support/com.tinyapp.TablePlus/Data/Connections.plist`。
|
||||
|
||||
**快速配置脚本**(已包含本地和远程连接):
|
||||
|
||||
```bash
|
||||
# 1. 关闭 TablePlus(如果正在运行)
|
||||
killall TablePlus 2>/dev/null || true
|
||||
|
||||
# 2. 备份现有配置
|
||||
cp ~/Library/Application\ Support/com.tinyapp.TablePlus/Data/Connections.plist \
|
||||
~/Library/Application\ Support/com.tinyapp.TablePlus/Data/Connections.plist.backup
|
||||
|
||||
# 3. 编辑配置文件添加连接(参考下方 plist 格式)
|
||||
|
||||
# 4. 重启 TablePlus
|
||||
open -a TablePlus
|
||||
```
|
||||
|
||||
**连接配置示例**(plist 格式):
|
||||
|
||||
```xml
|
||||
<!-- 本地开发环境连接 -->
|
||||
<dict>
|
||||
<key>ConnectionName</key>
|
||||
<string>Coolbuy PaaS - Local (开发环境)</string>
|
||||
<key>DatabaseHost</key>
|
||||
<string>localhost</string>
|
||||
<key>DatabasePort</key>
|
||||
<string>5432</string>
|
||||
<key>DatabaseName</key>
|
||||
<string>paas_foundation</string>
|
||||
<key>DatabaseUser</key>
|
||||
<string>coolbuy-dev</string>
|
||||
<key>DatabasePasswordMode</key>
|
||||
<integer>0</integer>
|
||||
<key>Driver</key>
|
||||
<string>PostgreSQL</string>
|
||||
<key>Enviroment</key>
|
||||
<string>local</string>
|
||||
<key>statusColor</key>
|
||||
<string>#3B82F6</string> <!-- 蓝色标识开发环境 -->
|
||||
</dict>
|
||||
```
|
||||
|
||||
#### 手动配置步骤
|
||||
|
||||
如果自动配置失败,可以手动在 TablePlus GUI 中添加:
|
||||
|
||||
1. 打开 TablePlus → 点击 "Create a new connection"
|
||||
2. 选择 PostgreSQL
|
||||
3. 填写连接信息:
|
||||
|
||||
**本地连接**:
|
||||
- Name: `Coolbuy PaaS - Local (开发环境)`
|
||||
- Host: `localhost`
|
||||
- Port: `5432`
|
||||
- Database: `paas_foundation`
|
||||
- User: `coolbuy-dev`
|
||||
- Password: (留空)
|
||||
- Color: 蓝色
|
||||
|
||||
**生产连接**:
|
||||
- Name: `Coolbuy PaaS - Production (生产环境)`
|
||||
- Host: `192.144.137.14`
|
||||
- Port: `5432`
|
||||
- Database: `coolbuy_paas`
|
||||
- User: `platform`
|
||||
- Password: `Zhiyuncai2025~`
|
||||
- Color: 红色(警示)
|
||||
- **重要**:勾选 "Read-only mode" 防止误操作
|
||||
|
||||
#### 验证连接
|
||||
|
||||
连接成功后运行以下 SQL 验证:
|
||||
|
||||
```sql
|
||||
-- 检查数据库版本
|
||||
SELECT version();
|
||||
|
||||
-- 查看所有表
|
||||
SELECT table_schema, table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
ORDER BY table_schema, table_name;
|
||||
|
||||
-- 查看库存预占记录
|
||||
SELECT * FROM biz_inventory_reservations
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 10;
|
||||
|
||||
-- 查看活跃租户
|
||||
SELECT id, name, code, status
|
||||
FROM fnd_tenants
|
||||
WHERE status = 1 AND deleted_at IS NULL;
|
||||
```
|
||||
|
||||
#### TablePlus 常用快捷键
|
||||
|
||||
| 快捷键 | 功能 |
|
||||
|--------|------|
|
||||
| `Cmd + N` | 新建连接 |
|
||||
| `Cmd + T` | 新建 Tab |
|
||||
| `Cmd + K` | 连接列表 |
|
||||
| `Cmd + R` | 刷新 |
|
||||
| `Cmd + /` | 注释/取消注释 SQL |
|
||||
| `Cmd + Enter` | 执行 SQL |
|
||||
| `Cmd + Shift + E` | 导出数据 |
|
||||
|
||||
#### 安全提示
|
||||
|
||||
⚠️ **生产数据库操作注意事项**:
|
||||
|
||||
1. **必须**启用 "Read-only mode"(连接设置中)
|
||||
2. **避免**直接执行 UPDATE/DELETE 操作
|
||||
3. **建议**使用事务测试:`BEGIN; ... ROLLBACK;`
|
||||
4. **慎用**批量操作
|
||||
5. **定期**备份重要数据
|
||||
|
||||
---
|
||||
|
||||
## 独立商城 (web-mall)
|
||||
|
||||
独立 B2B 商城前端,与租户端 `web/` 并行运行,共享后端 API。
|
||||
|
||||
### 定位对比
|
||||
|
||||
| 维度 | 租户端 (web/) | 独立商城 (web-mall/) |
|
||||
|------|--------------|---------------------|
|
||||
| 定位 | 内部采购经理 | 终端采购用户 |
|
||||
| 布局 | ERP 侧边栏 | 商城顶部导航 |
|
||||
| 选品 | 表单弹窗选择 | 浏览分类/搜索+加购 |
|
||||
| 下单 | ERP 表单模式 | 购物车→结算 |
|
||||
|
||||
### 页面结构
|
||||
|
||||
| 页面 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| 首页 | `/` | 推荐商品、分类入口 |
|
||||
| 商品列表 | `/products` | 搜索、筛选、排序 |
|
||||
| 商品详情 | `/products/:id` | SKU 选择、加入购物车 |
|
||||
| 购物车 | `/cart` | 购物车管理 |
|
||||
| 结算 | `/checkout` | 提交订单 |
|
||||
| 个人中心 | `/user` | 订单列表、订单详情 |
|
||||
|
||||
### Vite 代理配置 (web-mall/vite.config.ts)
|
||||
|
||||
```typescript
|
||||
proxy: {
|
||||
'/api/v1/auth': { target: 'http://localhost:7089' }, // auth-service
|
||||
'/api': { target: 'http://localhost:7091' }, // erp-service
|
||||
}
|
||||
```
|
||||
|
||||
### Docker 部署
|
||||
|
||||
| 环境 | 端口 | 镜像 |
|
||||
|------|------|------|
|
||||
| 开发 | 5174 (Vite) | 本地 `npm run dev` |
|
||||
| 生产 | 8889:80 | `saltthing123/coolbuy-paas-web-mall` |
|
||||
|
||||
### 需求来源
|
||||
|
||||
REQ-20260214-0001(采购单双模式),PRD 任务 #5874。
|
||||
|
||||
---
|
||||
|
||||
## 商品模块开发
|
||||
|
||||
### 前端页面结构
|
||||
|
||||
```
|
||||
web/src/pages/Product/
|
||||
├── ProductList/ # 商品列表页
|
||||
│ ├── index.tsx
|
||||
│ ├── columns.tsx # 表格列配置
|
||||
│ └── searchFields.ts # 搜索表单配置
|
||||
├── ProductForm/ # 商品表单页(新增/编辑)
|
||||
│ ├── index.tsx
|
||||
│ ├── BasicInfo.tsx # 基本信息
|
||||
│ ├── ImageUpload.tsx # 图片上传
|
||||
│ └── PriceInfo.tsx # 价格信息
|
||||
└── ProductDetail/ # 商品详情弹窗
|
||||
└── index.tsx
|
||||
```
|
||||
|
||||
### 后端模块结构
|
||||
|
||||
```
|
||||
erp-service/internal/product/
|
||||
├── model/
|
||||
│ ├── spu.go # SPU 模型
|
||||
│ └── sku.go # SKU 模型
|
||||
├── biz/
|
||||
│ ├── spu.go # SPU 业务逻辑
|
||||
│ └── sku.go # SKU 业务逻辑
|
||||
├── store/
|
||||
│ ├── spu.go # SPU 数据访问
|
||||
│ └── sku.go # SKU 数据访问
|
||||
└── handler/
|
||||
└── spu_handler.go # HTTP 处理器
|
||||
```
|
||||
|
||||
### API 端点
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | /api/v1/products | 商品列表 |
|
||||
| GET | /api/v1/products/:id | 商品详情 |
|
||||
| POST | /api/v1/products | 创建商品 |
|
||||
| PUT | /api/v1/products/:id | 更新商品 |
|
||||
| DELETE | /api/v1/products/:id | 删除商品 |
|
||||
| PATCH | /api/v1/products/:id/status | 上架/下架 |
|
||||
|
||||
---
|
||||
|
||||
## 研发经验与开发策略
|
||||
|
||||
> 本章总结了酷采 3.0 开发过程中积累的研发方法论,指导 Claude Code 高效完成业务模块开发。
|
||||
|
||||
### 系统定位
|
||||
|
||||
酷采 3.0 是酷采 2.0 的**重构升级版本**,不是 1:1 复刻。核心策略:**用 2.0 的业务逻辑 + 3.0 的代码模式**。
|
||||
|
||||
### 两代系统架构对比
|
||||
|
||||
| 维度 | 酷采 2.0 (coolbuy-legacy) | 酷采 3.0 (coolbuy-paas) |
|
||||
|------|--------------------------|------------------------|
|
||||
| 后端 | Java Spring Boot 单体 | Go 微服务 (5 个独立服务) |
|
||||
| 前端 | Vue 2 + Element UI | React 18 + Ant Design 5 + Vite |
|
||||
| 数据库 | MySQL + MyBatis | PostgreSQL + GORM |
|
||||
| 认证 | Shiro | JWT + Redis 黑名单 |
|
||||
| 多租户 | company_id 字段 | 原生 SaaS tenant 隔离 |
|
||||
| 权限 | 多表关联 RBAC | 权限引擎 + 数据权限 |
|
||||
|
||||
### 业务模块完成度
|
||||
|
||||
| 业务模块 | 2.0 页面 | 3.0 后端 | 3.0 前端 | 优先级 |
|
||||
|----------|---------|---------|---------|--------|
|
||||
| 系统管理 (用户/角色/权限/组织) | 9 页 | 95% | 95% | - 已完成 |
|
||||
| 商品管理 (SPU/SKU/分类/品牌) | 18 页 | 90% | 85% | P1 补齐 |
|
||||
| 订单管理 (销售/采购/退货/审批) | 22 页 | 85% | 70% | **P0** |
|
||||
| 仓储管理 (入库/出库/库存/物流) | 6 页 | 70% | 50% | P0 |
|
||||
| 客户管理 (等级/销售员/供应商) | 17 页 | 60% | 50% | P0 |
|
||||
| 财务结算 (账户/流水/结算单) | 3 页 | 40% | 30% | P1 |
|
||||
| 报备授权 (项目/渠道/审核) | 20+ 页 | 20% | 10% | P2 评估 |
|
||||
| 分销网络 (3.0 新增) | 无 | 75% | 75% | P1 |
|
||||
| 购物车 & 商城 (web-mall) | 无 | 80% | 80% | P1 |
|
||||
|
||||
### 三层工作流 (需求 → 代码)
|
||||
|
||||
```
|
||||
第一层: 需求 → PRD (/req-prd skill)
|
||||
输入: 2.0 对应页面 + 业务规则描述
|
||||
输出: PRD 文档 + 原型 HTML (dev-plans/prototypes/)
|
||||
工具: /req create → /req doc
|
||||
|
||||
第二层: PRD → 开发计划 (/req-dev skill)
|
||||
输入: PRD + 当前 3.0 代码库分析
|
||||
输出: 文件级开发任务拆分
|
||||
工具: /req doc → ai-proj tasks
|
||||
|
||||
第三层: 任务 → 代码 (/dev-coding skill)
|
||||
输入: 开发计划 + 参考模块代码
|
||||
输出: 可运行的前后端代码
|
||||
工具: Claude Code 直接编码
|
||||
```
|
||||
|
||||
### 模块复制模式 (核心开发方法)
|
||||
|
||||
每个新业务模块参照已有成熟模块的代码模式生成:
|
||||
|
||||
```
|
||||
参考模块 (User) 目标模块 (Order)
|
||||
──────────────────── ────────────────────
|
||||
api/types.ts (追加接口) → OrderQueryParams, Order, OrderItem...
|
||||
api/order.ts (新建) → getOrderList, getOrderById, createOrder...
|
||||
pages/OrderList.tsx → 统计卡片 + 搜索表单 + 工具栏 + 表格
|
||||
pages/OrderDetail.tsx → 头部信息 + 多 Tab (基本信息/明细/日志)
|
||||
pages/OrderForm.tsx → Modal 表单 (新增/编辑)
|
||||
router/tenantRoutes.tsx → 追加路由注册
|
||||
```
|
||||
|
||||
**关键约定**(必须遵循):
|
||||
- API 字段使用 `snake_case` (如 `order_status`, `created_at`)
|
||||
- 响应数据解包:`res.data?.data || res.data`(双层嵌套兼容)
|
||||
- 分页参数:`{ current, pageSize }` → 后端映射为 `{ page, page_size }`
|
||||
- 时间格式化:`dayjs(v).format('YYYY-MM-DD HH:mm:ss')`
|
||||
- 枚举渲染:`<Tag color={colorMap[value]}>{labelMap[value]}</Tag>`
|
||||
- 表格滚动:`scroll={{ x: 列宽总和 }}`
|
||||
- 权限控制:`<Permission permission="module:resource:action">` 包裹按钮
|
||||
|
||||
### 单模块开发 SOP
|
||||
|
||||
| 步骤 | 产出 | 预估时间 |
|
||||
|------|------|---------|
|
||||
| 1. 类型定义 | `types.ts` 追加接口/枚举 | 10 min |
|
||||
| 2. API 层 | `api/xxx.ts` (CRUD + 业务接口) | 10 min |
|
||||
| 3. 列表页 | `XxxList.tsx` (搜索+表格+工具栏+统计) | 20 min |
|
||||
| 4. 详情页 | `XxxDetail.tsx` (多 Tab 信息展示) | 20 min |
|
||||
| 5. 表单页 | `XxxForm.tsx` (新增/编辑 Modal) | 15 min |
|
||||
| 6. 路由注册 | `tenantRoutes.tsx` 追加 lazy import | 5 min |
|
||||
| 7. 联调修复 | 对接实际 API 后的字段/格式调整 | 30 min |
|
||||
|
||||
**单模块总计约 2 小时**,相比纯手写 2-3 天。
|
||||
|
||||
### 参考 2.0 代码的方法
|
||||
|
||||
开发新模块时,Claude 应按以下顺序获取业务知识:
|
||||
|
||||
```bash
|
||||
# 1. 读 2.0 前端路由 → 了解页面结构和导航
|
||||
~/workspace/coolbuy-paas/coolbuy-legacy/ln_admin/src/router/<module>_routers.js
|
||||
|
||||
# 2. 读 2.0 前端页面 → 了解字段、搜索条件、操作按钮
|
||||
~/workspace/coolbuy-paas/coolbuy-legacy/ln_admin/src/views/module/<module>/
|
||||
|
||||
# 3. 读 2.0 后端 Manager → 了解业务规则和校验逻辑
|
||||
~/workspace/coolbuy-paas/coolbuy-legacy/cool_belle/module-provider/src/main/java/com/jzg/module/manager/<module>/
|
||||
|
||||
# 4. 读 2.0 数据模型 → 了解表结构和字段
|
||||
~/workspace/coolbuy-paas/coolbuy-legacy/cool_belle/module-provider/src/main/java/com/jzg/module/dao/model/<module>/
|
||||
|
||||
# 5. 读 3.0 已有参考模块 → 了解代码模式
|
||||
~/coding/qiudl/coolbuy-paas/web/src/modules/foundation/pages/User/
|
||||
~/coding/qiudl/coolbuy-paas/erp-service/internal/<module>/
|
||||
```
|
||||
|
||||
### 联调经验总结
|
||||
|
||||
以下是已验证的联调常见问题和修复模式:
|
||||
|
||||
| 问题 | 原因 | 修复模式 |
|
||||
|------|------|---------|
|
||||
| 表格空数据 | API 响应格式 `{list,total}` vs `data[]` | `const d = res.data?.data \|\| res.data; setList(d?.list \|\| d)` |
|
||||
| 按钮不显示 | Permission 组件依赖 `hasPermission()` | 确保 `isSuperAdmin()` 包含 `admin` 角色 |
|
||||
| 时间显示原始 ISO | 缺少 dayjs 格式化 | 统一用 `formatTime()` helper |
|
||||
| 统计接口 404 | 后端未部署 | `catch {}` 静默处理,不弹错误 |
|
||||
| "加载更多"覆盖数据 | setState 替换而非追加 | 加 `append` 参数:`prev => append ? [...prev, ...newList] : newList` |
|
||||
| TreeSelect undefined | 组织树数据映射缺字段 | 确保 `convertTreeData` 映射 `title/value/key` |
|
||||
| TS 类型不匹配 | API 返回结构与类型定义不一致 | 用 `: any` 断言,后续补齐类型 |
|
||||
| antd deprecated | v5.26 废弃 API | `bordered={false}` → `variant="borderless"` |
|
||||
|
||||
### 分阶段推进计划
|
||||
|
||||
**Phase 1 — 核心交易闭环** (决定系统可用性)
|
||||
- 订单管理:后端 handler 已有 507 行,前端 20 页面待联调
|
||||
- 客户管理:基础 CRUD + 客户等级 + 销售员体系
|
||||
- 仓储管理:入库/出库/库存查询
|
||||
|
||||
**Phase 2 — 商品完善 + 财务**
|
||||
- 商品模块补齐:组合方案、现货加标、生效时间管理
|
||||
- 财务结算:账户管理、流水查询、结算单
|
||||
|
||||
**Phase 3 — 运营支撑**
|
||||
- 报备/授权模块(评估后选择性迁移,2.0 有 20+ 页面)
|
||||
- 报表/数据分析
|
||||
- 小程序/H5 商城增强
|
||||
|
||||
### 2.0 订单模块业务知识 (已梳理)
|
||||
|
||||
#### 订单状态机
|
||||
|
||||
```
|
||||
创建 → 待支付(01) → 已支付(02) → 已发货(03) → 已收货(04) → 已完成(10)
|
||||
↘ 已取消(05) ↘ 已退款(08)
|
||||
待审核(06) 已关闭(07)
|
||||
待出库(11)
|
||||
```
|
||||
|
||||
#### 支付方式
|
||||
|
||||
| 代码 | 方式 | 业务规则 |
|
||||
|------|------|---------|
|
||||
| 01 | 预存款 | 扣减预付账户余额,记 BizFundLog |
|
||||
| 02 | 授信 | 扣减信用额度,需审核 |
|
||||
| 11 | 银行转账 | 自动生成付款单(MallPay)+收款单(MallReceive) |
|
||||
| 13 | 货到付款 | 无需预付 |
|
||||
|
||||
#### 退款类型
|
||||
|
||||
| 类型 | 说明 | 校验规则 |
|
||||
|------|------|---------|
|
||||
| 整单退(01) | 全额退款 | 同一用户/订单只能有一个待处理退款 |
|
||||
| 按数量退(02) | 部分数量退 | 检查可退数量 |
|
||||
| 按物品退(03) | 指定商品退 | 逐项检查 |
|
||||
| 退运费(04) | 仅退运费 | 运费大于 0 |
|
||||
|
||||
#### 用户角色与操作权限
|
||||
|
||||
| userType | 身份 | 可执行操作 |
|
||||
|----------|------|-----------|
|
||||
| 01 | 平台管理员 | 直接取消、审核、改价、所有操作 |
|
||||
| 02 | 供应商 | 申请退款、查看、发货 |
|
||||
| 03 | 客户 | 申请退款、查看、收货确认 |
|
||||
| 04 | 前端用户 | 下单、查看、基础操作 |
|
||||
|
||||
### 3.0 订单模块现状 (已梳理)
|
||||
|
||||
#### 后端 API (erp-service)
|
||||
|
||||
```
|
||||
GET /api/v1/orders # 列表 (支持 OrderNo/Status/Date/Amount 筛选)
|
||||
GET /api/v1/orders/:id # 详情 (含 items)
|
||||
POST /api/v1/orders # 创建 (含采购权限/区域/MOQ 校验)
|
||||
PUT /api/v1/orders/:id # 更新 (仅草稿)
|
||||
DELETE /api/v1/orders/:id # 删除 (仅草稿)
|
||||
POST /api/v1/orders/:id/submit-approval # 提交审批
|
||||
POST /api/v1/orders/:id/approve # 审批通过/拒绝
|
||||
POST /api/v1/orders/:id/confirm-payment # 确认付款
|
||||
POST /api/v1/orders/:id/ship # 发货
|
||||
POST /api/v1/orders/:id/confirm-delivery # 确认收货
|
||||
POST /api/v1/orders/:id/complete # 完成
|
||||
POST /api/v1/orders/:id/cancel # 取消
|
||||
POST /api/v1/orders/:id/refund # 退款
|
||||
GET /api/v1/orders/:id/status-logs # 状态变更日志
|
||||
GET /api/v1/orders/:id/approval-history # 审批历史
|
||||
GET /api/v1/orders/statistics/* # 统计 (6 个子接口)
|
||||
```
|
||||
|
||||
#### 3.0 订单状态 (14 态,比 2.0 更细)
|
||||
|
||||
```
|
||||
Draft(10) → PendingApproval(20) → Approved(29) → PendingPayment(30) → Paid(39)
|
||||
→ PendingShipment(40) → PartialShipped(45) → Shipped(49)
|
||||
→ PartialDelivered(55) → Delivered(59) → Completed(90)
|
||||
→ Rejected(92) / Cancelled(95) / Refunded(97)
|
||||
```
|
||||
|
||||
#### 前端已有页面 (20 个)
|
||||
|
||||
```
|
||||
/order/sales - SalesOrderList
|
||||
/order/sales/add - SalesOrderForm
|
||||
/order/business - BusinessOrderList
|
||||
/order/purchase - PurchaseOrderList
|
||||
/order/purchase/add - PurchaseOrderForm
|
||||
/order/purchase/:id - PurchaseOrderDetail
|
||||
/order/pending-approval - PendingApprovalList
|
||||
/order/return - ReturnOrderList
|
||||
/order/return/create - CreateReturnOrder
|
||||
/order/return/:id - ReturnOrderDetail
|
||||
/order/statistics - PurchaseOrderStatistics
|
||||
/checkout - CheckoutPage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关技能
|
||||
|
||||
- `coolbuy-platform` - 平台管理端开发
|
||||
- `coolbuy-legacy` - 酷采 2.0 测试与参考
|
||||
- `dev-coding` - 软件编码开发
|
||||
- `dev-arch` - 软件架构设计
|
||||
- `dev-test` - 软件测试
|
||||
- `req-prd` - 产品需求文档编写
|
||||
- `req-dev` - 需求开发计划编写
|
||||
- `siyuan` - 思源笔记(含酷采相关文档)
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| 1.4.0 | 2026-02-25 | 新增研发经验与开发策略章节:两代系统对比、模块完成度、三层工作流、模块复制模式、联调经验、订单模块业务梳理 |
|
||||
| 1.3.0 | 2026-02-14 | 新增数据库管理工具章节:TablePlus 安装配置、自动配置脚本、连接验证、安全提示 |
|
||||
| 1.2.0 | 2026-02-14 | 新增 web-mall 独立商城模块(架构、页面、代理、部署端口) |
|
||||
| 1.1.0 | 2026-02-13 | 新增 AI Chat 代码路径、认证链路、关键文件说明;记录 aiChatApi vs aiChatService 陷阱 |
|
||||
| 1.0.0 | 2026-01-10 | 初始版本,添加酷采2.0测试环境和浏览器自动化指南 |
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "coolbuy-platform-plugin",
|
||||
"description": "Coolbuy SaaS 平台管理端开发与部署。用于平台端前后端开发、租户管理、部署发布、翻译检查等任务。",
|
||||
"version": "1.0.9",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,338 +0,0 @@
|
||||
---
|
||||
name: coolbuy-platform
|
||||
description: Coolbuy SaaS 平台管理端开发与部署。用于平台端前后端开发、租户管理、部署发布、翻译检查等任务。当用户提到 coolbuy-platform、平台端、租户管理后台相关任务时自动激活。
|
||||
---
|
||||
|
||||
# Coolbuy Platform Skill
|
||||
|
||||
Coolbuy SaaS 平台管理端,用于管理所有租户、功能授权、计费、运营分析等。
|
||||
|
||||
## 项目信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本地路径 | `/Users/donglinlai/coding/qiudl/coolbuy-platform` |
|
||||
| Git 仓库 | `git@gitea.pipexerp.com:pipexerp/coolbuy-platform.git` |
|
||||
| 主分支 | main |
|
||||
|
||||
---
|
||||
|
||||
## 架构概览
|
||||
|
||||
```
|
||||
coolbuy-platform/
|
||||
├── service/ # Go 后端 (Gin + GORM)
|
||||
│ ├── cmd/ # 入口 main.go
|
||||
│ ├── internal/admin/ # 核心业务
|
||||
│ │ ├── api/ # HTTP handlers
|
||||
│ │ ├── biz/ # 业务逻辑
|
||||
│ │ ├── store/ # 数据访问
|
||||
│ │ ├── model/ # 领域模型
|
||||
│ │ └── middleware/ # 中间件
|
||||
│ └── configs/ # 配置文件
|
||||
└── web/ # React 前端 (Vite + TypeScript)
|
||||
├── src/
|
||||
│ ├── api/ # API 客户端
|
||||
│ ├── components/ # 组件
|
||||
│ ├── pages/ # 页面
|
||||
│ ├── stores/ # Zustand 状态
|
||||
│ └── locales/ # i18n 翻译
|
||||
└── dist/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 部署环境
|
||||
|
||||
### 生产服务器
|
||||
|
||||
| 服务 | 地址 | 端口 | 容器名 |
|
||||
|------|------|------|--------|
|
||||
| 前端 | http://platform.pipexerp.com | 4999 | coolbuy-platform-web |
|
||||
| 后端 | http://39.105.150.219 | 7090 | coolbuy-platform-service |
|
||||
| Auth | http://39.105.150.219 | 7089 | coolbuy-auth-service |
|
||||
|
||||
### 服务器信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| IP | 39.105.150.219 |
|
||||
| 用户 | root |
|
||||
| SSH 密钥 | ~/.ssh/coolbuy3.pem |
|
||||
| 操作系统 | Ubuntu 24.04 |
|
||||
|
||||
### 数据库
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 类型 | PostgreSQL 16 |
|
||||
| Host | 172.18.0.1 (Docker 网关) |
|
||||
| Port | 5432 |
|
||||
| Database | paas_platform |
|
||||
| User | platform |
|
||||
| Password | Coolbuy2025~ |
|
||||
|
||||
### Docker Registry
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| Registry | Docker Hub |
|
||||
| 账号 | saltthing123 |
|
||||
| 前端镜像 | saltthing123/coolbuy-platform-web |
|
||||
| 后端镜像 | saltthing123/coolbuy-platform-service |
|
||||
| Auth镜像 | saltthing123/coolbuy-auth-service |
|
||||
|
||||
---
|
||||
|
||||
## 快速部署命令
|
||||
|
||||
### 部署前端
|
||||
|
||||
```bash
|
||||
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/web
|
||||
|
||||
# 1. 构建
|
||||
npx vite build
|
||||
|
||||
# 2. 打包 Docker 镜像
|
||||
~/.orbstack/bin/docker build --platform linux/amd64 \
|
||||
-t saltthing123/coolbuy-platform-web:<version> \
|
||||
-t saltthing123/coolbuy-platform-web:latest .
|
||||
|
||||
# 3. 推送镜像
|
||||
~/.orbstack/bin/docker push saltthing123/coolbuy-platform-web:<version>
|
||||
~/.orbstack/bin/docker push saltthing123/coolbuy-platform-web:latest
|
||||
|
||||
# 4. 部署到服务器
|
||||
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "
|
||||
docker pull saltthing123/coolbuy-platform-web:<version> && \
|
||||
docker stop coolbuy-platform-web && \
|
||||
docker rm coolbuy-platform-web && \
|
||||
docker run -d --name coolbuy-platform-web \
|
||||
--restart unless-stopped \
|
||||
-p 4999:80 \
|
||||
saltthing123/coolbuy-platform-web:<version>
|
||||
"
|
||||
```
|
||||
|
||||
### 部署后端
|
||||
|
||||
```bash
|
||||
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/service
|
||||
|
||||
# 1. 构建二进制
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o coolbuy-platform-service cmd/main.go
|
||||
|
||||
# 2. 打包 Docker 镜像
|
||||
~/.orbstack/bin/docker build --platform linux/amd64 \
|
||||
-t saltthing123/coolbuy-platform-service:<version> \
|
||||
-t saltthing123/coolbuy-platform-service:latest .
|
||||
|
||||
# 3. 推送镜像
|
||||
~/.orbstack/bin/docker push saltthing123/coolbuy-platform-service:<version>
|
||||
~/.orbstack/bin/docker push saltthing123/coolbuy-platform-service:latest
|
||||
|
||||
# 4. 部署到服务器
|
||||
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "
|
||||
docker pull saltthing123/coolbuy-platform-service:<version> && \
|
||||
docker stop coolbuy-platform-service && \
|
||||
docker rm coolbuy-platform-service && \
|
||||
docker run -d --name coolbuy-platform-service \
|
||||
--restart unless-stopped \
|
||||
-p 7090:7090 \
|
||||
-v /data/coolbuy-platform/logs:/app/logs \
|
||||
-v /data/coolbuy-platform/storage:/app/storage \
|
||||
-v /data/coolbuy-platform/configs:/app/configs:ro \
|
||||
-e TZ=Asia/Shanghai \
|
||||
saltthing123/coolbuy-platform-service:<version> \
|
||||
--config configs/config.prod.yaml
|
||||
"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 本地开发
|
||||
|
||||
### 启动后端
|
||||
|
||||
```bash
|
||||
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/service
|
||||
go run cmd/main.go -config configs/config-dev.yaml
|
||||
```
|
||||
|
||||
### 启动前端
|
||||
|
||||
```bash
|
||||
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/web
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 构建测试
|
||||
|
||||
```bash
|
||||
# 后端测试
|
||||
cd service && go test -v ./...
|
||||
|
||||
# 前端测试
|
||||
cd web && npm run test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 翻译管理
|
||||
|
||||
### 翻译文件位置
|
||||
|
||||
- 简体中文: `web/src/locales/zh-CN.ts`
|
||||
- 繁体中文: `web/src/locales/zh-TW.ts`
|
||||
|
||||
### 检查翻译缺失
|
||||
|
||||
```bash
|
||||
# 查找组件中使用的翻译 key
|
||||
cd /Users/donglinlai/coding/qiudl/coolbuy-platform/web
|
||||
grep -r "t(['\"]" src/components/ src/pages/ | grep -oE "t\(['\"][^'\"]+['\"]" | sort | uniq
|
||||
```
|
||||
|
||||
### 翻译 key 命名规范
|
||||
|
||||
| 模块 | 前缀 | 示例 |
|
||||
|------|------|------|
|
||||
| 租户管理 | tenant.* | tenant.form.nameRequired |
|
||||
| 用户管理 | user.* | user.createSuccess |
|
||||
| 角色管理 | role.* | role.permissionAssigned |
|
||||
| 菜单管理 | menu.* | menu.iconRequired |
|
||||
| 通知中心 | notification.* | notification.markAllRead |
|
||||
|
||||
---
|
||||
|
||||
## API 端点
|
||||
|
||||
### 认证 (Auth Service - 7089)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| POST | /api/v1/auth/login | 登录 |
|
||||
| POST | /api/v1/auth/logout | 登出 |
|
||||
| POST | /api/v1/auth/refresh | 刷新 Token |
|
||||
|
||||
### 平台管理 (Platform Service - 7090)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| GET | /api/v1/admin/tenants | 租户列表 |
|
||||
| POST | /api/v1/admin/tenants | 创建租户 |
|
||||
| GET | /api/v1/admin/users | 用户列表 |
|
||||
| GET | /api/v1/admin/roles | 角色列表 |
|
||||
| GET | /api/v1/admin/menus | 菜单列表 |
|
||||
| GET | /api/v1/admin/dashboard/overview | 仪表盘概览 |
|
||||
|
||||
### 健康检查
|
||||
|
||||
| 路径 | 说明 |
|
||||
|------|------|
|
||||
| /health | 基础健康检查 |
|
||||
| /health/detailed | 详细状态 |
|
||||
| /readiness | K8s 就绪探针 |
|
||||
| /liveness | K8s 存活探针 |
|
||||
|
||||
---
|
||||
|
||||
## 数据库迁移
|
||||
|
||||
### 自动迁移
|
||||
|
||||
配置 `migration.auto: true` 时,服务启动自动运行迁移。
|
||||
|
||||
### 手动迁移
|
||||
|
||||
```bash
|
||||
psql -h 172.18.0.1 -U platform -d paas_platform \
|
||||
-f service/configs/migrations/001_create_platform_admin_tables.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 翻译 key 不显示
|
||||
|
||||
组件使用的 key 与 locale 定义不匹配。检查:
|
||||
- 组件使用 `t('tenant.domainConfig.*')` 但 locale 定义为 `tenant.domain.*`
|
||||
- 需要添加别名命名空间
|
||||
|
||||
### 2. SSE 连接错误
|
||||
|
||||
通过 Cloudflare Tunnel 访问时 SSE 长连接会中断,属于已知问题,会自动重连。
|
||||
|
||||
### 3. Docker 构建失败
|
||||
|
||||
确保使用 OrbStack 的 docker:`~/.orbstack/bin/docker`
|
||||
|
||||
### 4. 数据库连接失败
|
||||
|
||||
Docker 网关 IP 是 `172.18.0.1`,不是默认的 `172.17.0.1`。
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| 1.0.9 | 2026-01-05 | 修复租户管理全部翻译缺失 |
|
||||
| 1.0.8 | 2026-01-04 | 修复租户列表翻译 |
|
||||
| 1.0.7 | 2026-01-04 | 修复租户表单翻译 |
|
||||
| 1.0.0 | 2026-01-03 | 初始版本 |
|
||||
|
||||
---
|
||||
|
||||
## SSH 快捷命令
|
||||
|
||||
```bash
|
||||
# 连接服务器
|
||||
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219
|
||||
|
||||
# 查看容器状态
|
||||
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "docker ps | grep coolbuy"
|
||||
|
||||
# 查看后端日志
|
||||
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "docker logs -f coolbuy-platform-service --tail 100"
|
||||
|
||||
# 查看前端日志
|
||||
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "docker logs -f coolbuy-platform-web --tail 100"
|
||||
|
||||
# 健康检查
|
||||
ssh -i ~/.ssh/coolbuy3.pem root@39.105.150.219 "curl -s http://localhost:7090/health"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 创建租户
|
||||
|
||||
```bash
|
||||
# 通过 API 创建租户
|
||||
curl -X POST http://39.105.150.219:7090/api/v1/admin/tenants \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer <token>" \
|
||||
-d '{
|
||||
"name": "租户名称",
|
||||
"code": "tenant_code",
|
||||
"contact": "联系人",
|
||||
"phone": "13800138000",
|
||||
"email": "contact@example.com",
|
||||
"user_limit": 50,
|
||||
"storage_limit": 10,
|
||||
"schema_type": "shared",
|
||||
"admin_username": "tenantadmin",
|
||||
"admin_real_name": "管理员姓名",
|
||||
"status": "normal"
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 相关技能
|
||||
|
||||
- `ops-tools` - DevOps 运维工具,包含 Jenkins/Gitea 管理
|
||||
- `dev-coding` - 软件编码开发
|
||||
- `coolbuy-paas` - 租户端系统(待创建)
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "enjoysa-deploy-plugin",
|
||||
"description": "EnjoySA 项目部署到新加坡服务器",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
# EnjoySA 部署技能
|
||||
|
||||
## 触发条件
|
||||
|
||||
当用户提到以下内容时自动激活:
|
||||
- enjoysa 部署
|
||||
- 部署到新加坡
|
||||
- deploy enjoysa
|
||||
|
||||
---
|
||||
|
||||
## 项目信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本地路径 | `/Users/donglinlai/coding/qiudl/enjoysa` |
|
||||
| Git 仓库 | `https://gitea.pipexerp.com/qiudl/enjoysa.git` |
|
||||
| 主分支 | main |
|
||||
|
||||
---
|
||||
|
||||
## 服务器信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 服务器 | singapore (43.134.28.147) |
|
||||
| 用户 | ubuntu |
|
||||
| SSH 密钥 | ~/.ssh/singpore.pem |
|
||||
| 部署路径 | /opt/enjoysa |
|
||||
| 访问地址 | http://43.134.28.147:6066 |
|
||||
| Web 服务 | Nginx (端口 6066) |
|
||||
|
||||
---
|
||||
|
||||
## 快速部署
|
||||
|
||||
执行部署脚本:
|
||||
```bash
|
||||
./scripts/deploy.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 手动部署步骤
|
||||
|
||||
### 1. 构建
|
||||
```bash
|
||||
cd web && npm run build
|
||||
```
|
||||
|
||||
### 2. 上传
|
||||
```bash
|
||||
scp -r web/dist/* singapore:/opt/enjoysa/
|
||||
```
|
||||
|
||||
### 3. 验证
|
||||
```bash
|
||||
ssh singapore "curl -s -o /dev/null -w '%{http_code}' http://localhost:6066/"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常用运维命令
|
||||
|
||||
```bash
|
||||
# 查看 Nginx 状态
|
||||
ssh singapore "sudo systemctl status nginx"
|
||||
|
||||
# 重载 Nginx 配置
|
||||
ssh singapore "sudo nginx -t && sudo systemctl reload nginx"
|
||||
|
||||
# 查看部署目录
|
||||
ssh singapore "ls -la /opt/enjoysa/"
|
||||
|
||||
# 查看 Nginx 访问日志
|
||||
ssh singapore "sudo tail -f /var/log/nginx/access.log"
|
||||
|
||||
# 查看错误日志
|
||||
ssh singapore "sudo tail -f /var/log/nginx/error.log"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Nginx 配置
|
||||
|
||||
配置文件: `/etc/nginx/sites-available/enjoysa`
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 6066;
|
||||
listen [::]:6066;
|
||||
server_name _;
|
||||
root /opt/enjoysa;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 腾讯云安全组需开放 6066 端口
|
||||
2. SPA 应用使用 `try_files` 支持前端路由
|
||||
3. 静态资源设置长期缓存
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "enjoysa-plugin",
|
||||
"description": "Plugin for enjoysa",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
---
|
||||
name: enjoysa
|
||||
description: EnjoySA 畅游南澳旅游平台开发。用于前端页面开发、组件开发、i18n国际化。当用户提到 enjoysa、畅游南澳、旅游平台、供应商后台相关任务时自动激活。
|
||||
---
|
||||
|
||||
# EnjoySA 开发技能
|
||||
|
||||
畅游南澳旅游平台,面向 C 端游客和 B 端供应商的在线旅游服务系统。
|
||||
|
||||
## 项目信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 本地路径 | `/Users/donglinlai/coding/qiudl/enjoysa` |
|
||||
| Git 仓库 | `https://gitea.pipexerp.com/qiudl/enjoysa.git` |
|
||||
| 主分支 | main |
|
||||
| 技术栈 | Vite + React 18 + TypeScript + CSS Modules |
|
||||
| 部署服务器 | singapore (43.134.28.147:6066) |
|
||||
| 访问地址 | http://43.134.28.147:6066 |
|
||||
|
||||
---
|
||||
|
||||
## 架构概览
|
||||
|
||||
```
|
||||
enjoysa/
|
||||
├── web/ # React 前端
|
||||
│ ├── src/
|
||||
│ │ ├── components/ # 通用组件
|
||||
│ │ │ ├── Common/ # Header, Footer, LanguageSwitcher
|
||||
│ │ │ ├── Auth/ # LoginForm, RegisterForm
|
||||
│ │ │ └── Supplier/ # SupplierLoginForm, SupplierRegisterForm
|
||||
│ │ ├── pages/ # 页面组件
|
||||
│ │ │ ├── LoginPage/ # C端用户登录
|
||||
│ │ │ ├── SupplierLoginPage/# B端供应商登录
|
||||
│ │ │ ├── AdminLoginPage/ # 平台管理员登录
|
||||
│ │ │ ├── TermsPage/ # 服务条款
|
||||
│ │ │ ├── PrivacyPage/ # 隐私政策
|
||||
│ │ │ └── Supplier/ # 供应商后台模块
|
||||
│ │ ├── i18n/ # 国际化
|
||||
│ │ │ └── locales/ # 翻译文件
|
||||
│ │ │ ├── zh-CN.json
|
||||
│ │ │ └── en-US.json
|
||||
│ │ └── types/ # 类型定义
|
||||
│ ├── scripts/ # 部署脚本
|
||||
│ └── dist/ # 构建产物
|
||||
├── backend/ # Go 后端 (规划中)
|
||||
└── docs/ # 文档
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 页面路由
|
||||
|
||||
### C 端 (游客)
|
||||
|
||||
| 路由 | 页面 | 说明 |
|
||||
|------|------|------|
|
||||
| `/` | HomePage | 首页 |
|
||||
| `/login` | LoginPage | 用户登录/注册 |
|
||||
| `/terms` | TermsPage | 服务条款 |
|
||||
| `/privacy` | PrivacyPage | 隐私政策 |
|
||||
|
||||
### B 端 (供应商)
|
||||
|
||||
| 路由 | 页面 | 说明 |
|
||||
|------|------|------|
|
||||
| `/supplier/login` | SupplierLoginPage | 供应商登录 |
|
||||
| `/supplier/register` | SupplierRegisterPage | 供应商入驻申请 |
|
||||
| `/supplier` | SupplierDashboard | 供应商仪表盘 |
|
||||
| `/supplier/products` | SupplierProducts | 产品管理 |
|
||||
| `/supplier/orders` | SupplierOrders | 订单处理 |
|
||||
| `/supplier/finance` | SupplierFinance | 财务结算 |
|
||||
|
||||
### 管理端
|
||||
|
||||
| 路由 | 页面 | 说明 |
|
||||
|------|------|------|
|
||||
| `/admin/login` | AdminLoginPage | 管理员登录 |
|
||||
|
||||
---
|
||||
|
||||
## i18n 国际化
|
||||
|
||||
### 翻译文件位置
|
||||
|
||||
```
|
||||
web/src/i18n/locales/
|
||||
├── zh-CN.json # 简体中文
|
||||
└── en-US.json # 英文
|
||||
```
|
||||
|
||||
### 命名空间规范
|
||||
|
||||
| 命名空间 | 用途 | 示例 |
|
||||
|---------|------|------|
|
||||
| `brand.*` | 品牌信息 | brand.name, brand.tagline |
|
||||
| `auth.*` | 登录注册 | auth.loginTitle, auth.emailPlaceholder |
|
||||
| `terms.*` | 服务条款 | terms.title, terms.sections.* |
|
||||
| `privacy.*` | 隐私政策 | privacy.title, privacy.sections.* |
|
||||
| `supplier.*` | 供应商模块 | supplier.login.*, supplier.dashboard.* |
|
||||
| `admin.*` | 管理员模块 | admin.login.*, admin.dashboard.* |
|
||||
| `common.*` | 通用文本 | common.submit, common.cancel |
|
||||
| `footer.*` | 页脚 | footer.supplierEntry, footer.copyright |
|
||||
|
||||
### 添加新翻译步骤
|
||||
|
||||
1. 在 `zh-CN.json` 和 `en-US.json` 中同时添加新 key
|
||||
2. 使用 `useTranslation()` hook 获取 `t` 函数
|
||||
3. 使用 `t('namespace.key')` 获取翻译文本
|
||||
|
||||
```tsx
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const MyComponent = () => {
|
||||
const { t } = useTranslation();
|
||||
return <h1>{t('brand.name')}</h1>;
|
||||
};
|
||||
```
|
||||
|
||||
### 注意事项
|
||||
|
||||
- **禁止硬编码中文/英文**,所有用户可见文本必须使用 i18n
|
||||
- 长文本内容(如条款、政策)使用 `\n` 分段
|
||||
- JSON 中避免使用中文引号 `""` `''`,使用 `「」` 或英文引号
|
||||
|
||||
---
|
||||
|
||||
## 组件规范
|
||||
|
||||
### Common 组件
|
||||
|
||||
| 组件 | 用途 | 文件 |
|
||||
|------|------|------|
|
||||
| Header | 顶部导航栏 | `components/Common/Header/` |
|
||||
| Footer | 页脚(含供应商入口) | `components/Common/Footer/` |
|
||||
| LanguageSwitcher | 语言切换器 | `components/Common/LanguageSwitcher/` |
|
||||
|
||||
### Auth 组件
|
||||
|
||||
| 组件 | 用途 | 文件 |
|
||||
|------|------|------|
|
||||
| LoginForm | C端登录表单 | `components/Auth/LoginForm/` |
|
||||
| RegisterForm | C端注册表单 | `components/Auth/RegisterForm/` |
|
||||
|
||||
### Supplier 组件
|
||||
|
||||
| 组件 | 用途 | 文件 |
|
||||
|------|------|------|
|
||||
| SupplierLoginForm | 供应商登录表单 | `components/Supplier/SupplierLoginForm/` |
|
||||
| SupplierRegisterForm | 供应商入驻申请表单 | `components/Supplier/SupplierRegisterForm/` |
|
||||
|
||||
---
|
||||
|
||||
## 本地开发
|
||||
|
||||
### 启动前端
|
||||
|
||||
```bash
|
||||
cd /Users/donglinlai/coding/qiudl/enjoysa/web
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 构建
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 部署
|
||||
|
||||
```bash
|
||||
./scripts/deploy.sh
|
||||
```
|
||||
|
||||
或手动部署:
|
||||
```bash
|
||||
scp -r web/dist/* singapore:/opt/enjoysa/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 供应商类型
|
||||
|
||||
系统支持以下供应商类型:
|
||||
|
||||
| 类型 | 说明 |
|
||||
|------|------|
|
||||
| travel_agency | 旅行社 |
|
||||
| hotel | 酒店 |
|
||||
| attraction | 景区 |
|
||||
| restaurant | 餐厅 |
|
||||
| car_rental | 租车公司 |
|
||||
|
||||
---
|
||||
|
||||
## 相关技能
|
||||
|
||||
- `enjoysa-deploy` - 部署到新加坡服务器
|
||||
- `frontend-design` - 前端界面设计
|
||||
- `dev-coding` - 软件编码开发
|
||||
|
||||
---
|
||||
|
||||
## 版本历史
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| 1.0.0 | 2026-01-31 | 初始版本,包含项目结构、页面路由、i18n规范 |
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "executing-plans-plugin",
|
||||
"description": "Plugin for executing-plans",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
---
|
||||
name: executing-plans
|
||||
description: Use when you have a written implementation plan to execute in a separate session with review checkpoints
|
||||
---
|
||||
|
||||
# Executing Plans
|
||||
|
||||
## Overview
|
||||
|
||||
Load plan, review critically, create branch, execute tasks in batches, report for review between batches.
|
||||
|
||||
**Core principle:** Batch execution with checkpoints for architect review.
|
||||
|
||||
**Announce at start:** "I'm using the executing-plans skill to implement this plan."
|
||||
|
||||
## The Process
|
||||
|
||||
### Step 1: Load and Review Plan
|
||||
1. Read plan file
|
||||
2. Review critically - identify any questions or concerns about the plan
|
||||
3. If concerns: Raise them with your human partner before starting
|
||||
4. If no concerns: Proceed to branch setup
|
||||
|
||||
### Step 2: Setup Branch
|
||||
**Before any implementation, ensure proper branch isolation.**
|
||||
|
||||
1. Check if already on a feature branch for this task
|
||||
2. If not, use `/pr start` to create one:
|
||||
```bash
|
||||
/pr start <type> <REQ-id> <name>
|
||||
# Example: /pr start feature REQ-123 user-login
|
||||
```
|
||||
3. If no REQ-id available, ask user or create branch manually:
|
||||
```bash
|
||||
git fetch origin
|
||||
git checkout -b <type>/<descriptive-name> origin/main
|
||||
```
|
||||
4. Confirm branch is ready before proceeding
|
||||
|
||||
**Branch types:** `feature`, `fix`, `refactor`
|
||||
|
||||
### Step 3: Create Tasks and Execute Batch
|
||||
**Default: First 3 tasks**
|
||||
|
||||
1. Create TodoWrite tasks from plan
|
||||
2. For each task in batch:
|
||||
- Mark as in_progress
|
||||
- Follow each step exactly (plan has bite-sized steps)
|
||||
- Run verifications as specified
|
||||
- Mark as completed
|
||||
|
||||
### Step 4: Report
|
||||
When batch complete:
|
||||
- Show what was implemented
|
||||
- Show verification output
|
||||
- Say: "Ready for feedback."
|
||||
|
||||
### Step 5: Continue
|
||||
Based on feedback:
|
||||
- Apply changes if needed
|
||||
- Execute next batch
|
||||
- Repeat until complete
|
||||
|
||||
### Step 6: Complete Development
|
||||
|
||||
After all tasks complete and verified:
|
||||
- Announce: "I'm using the finishing-a-development-branch skill to complete this work."
|
||||
- **REQUIRED SUB-SKILL:** Use superpowers:finishing-a-development-branch
|
||||
- Follow that skill to verify tests, present options, execute choice
|
||||
|
||||
## When to Stop and Ask for Help
|
||||
|
||||
**STOP executing immediately when:**
|
||||
- Hit a blocker mid-batch (missing dependency, test fails, instruction unclear)
|
||||
- Plan has critical gaps preventing starting
|
||||
- You don't understand an instruction
|
||||
- Verification fails repeatedly
|
||||
|
||||
**Ask for clarification rather than guessing.**
|
||||
|
||||
## When to Revisit Earlier Steps
|
||||
|
||||
**Return to Review (Step 1) when:**
|
||||
- Partner updates the plan based on your feedback
|
||||
- Fundamental approach needs rethinking
|
||||
|
||||
**Don't force through blockers** - stop and ask.
|
||||
|
||||
## Remember
|
||||
- Review plan critically first
|
||||
- **Create feature branch before implementation**
|
||||
- Follow plan steps exactly
|
||||
- Don't skip verifications
|
||||
- Reference skills when plan says to
|
||||
- Between batches: just report and wait
|
||||
- Stop when blocked, don't guess
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "req-commands-plugin",
|
||||
"description": "需求命令详细参考。含撰写命令(new/draft/edit/check/split/history/compare)和流程命令(submit/review/phase/next/deploy/done)。",
|
||||
"version": "2.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,436 +0,0 @@
|
||||
---
|
||||
name: req-commands
|
||||
description: 需求命令详细参考。当需要查看 /req 命令的详细用法、参数、示例时使用。
|
||||
---
|
||||
|
||||
# req 命令参考
|
||||
|
||||
## 基础命令
|
||||
|
||||
### `/req` 或 `/req list`
|
||||
列出所有需求,按状态分组显示。
|
||||
|
||||
### `/req new [标题]`
|
||||
创建新需求。
|
||||
- 参数:`--priority=high|medium|low`,`--project=<name>`,`--category=feature|bug|improvement`
|
||||
- 创建后提示使用 `req-prd` 技能编写 PRD
|
||||
|
||||
### `/req status [REQ-ID]`
|
||||
查看需求详情、进度、关联任务。
|
||||
|
||||
## 阶段管理命令
|
||||
|
||||
### `/req phase [REQ-ID]`
|
||||
查看需求当前开发阶段和任务状态。
|
||||
|
||||
**执行逻辑**:
|
||||
1. `get_requirement(id)` → 获取 `delivery_stage`
|
||||
2. `get_requirement_tasks(id)` → 获取所有关联任务
|
||||
3. 按 linkRole 分组展示,标注当前阶段任务完成度
|
||||
|
||||
**输出示例**:
|
||||
```
|
||||
REQ-20260218-0013 | 阶段: dev (开发)
|
||||
────────────────────────────────────
|
||||
✅ analysis (评审)
|
||||
✅ #6035 【评审】PRD: 需求全生命周期阶段化管理
|
||||
✅ #6040 【评审】技术设计: 数据模型
|
||||
▶ dev (开发) ← 当前阶段
|
||||
🔄 #6042 【开发-后端】实现阶段管理 API [in_progress]
|
||||
⬜ #6043 【开发-前端】阶段可视化组件 [todo]
|
||||
⬜ review (代码评审)
|
||||
(无任务)
|
||||
⬜ testing (测试)
|
||||
(无任务)
|
||||
```
|
||||
|
||||
### `/req next [REQ-ID]`
|
||||
检测当前阶段完成度,推进到下一阶段。
|
||||
|
||||
**执行逻辑**:
|
||||
1. 获取当前 `delivery_stage` 和该阶段所有任务
|
||||
2. 检查任务完成度:
|
||||
- 全部完成 → 提示「当前阶段已完成,是否推进到 {下一阶段}?」
|
||||
- **部分未完成 → 显示未完成任务列表 + AskUserQuestion**:
|
||||
- 选项 A: "强制推进(需说明原因)"
|
||||
- 选项 B: "返回完成任务"
|
||||
- 用户选 A → 输入跳过原因 → `advance_delivery_stage(force=true)`
|
||||
- 记录到需求历史: `POST /requirements/{id}/history`,comment 包含跳过原因
|
||||
- **⚠️ 禁止 AI 自动使用 force=true,必须经过 AskUserQuestion 确认**
|
||||
3. **智能跳阶段检测**(推进前):
|
||||
- `get_requirement_tasks(id)` → 收集所有 linkRole
|
||||
- 如果目标阶段与当前 linkRole 不匹配,主动建议跳过:
|
||||
- 无 `implementation` → 推进到 review/testing 时提示「该需求无代码任务,建议跳过此阶段」
|
||||
- 无 `code_review` → 推进到 review 时提示跳过
|
||||
- 无 `test` → 推进到 testing 时提示跳过
|
||||
- 通过 AskUserQuestion 确认:「跳过」或「仍然创建任务」
|
||||
4. 用户确认推进后:
|
||||
- 更新 `delivery_stage` 到下一阶段
|
||||
- **自动创建**目标阶段的建议任务(`create_stage_task` 批量创建,无需询问)
|
||||
- 展示已创建任务列表:「✅ 已创建: #XXXX 【代码评审】CR: {需求标题}。如需撤销请说明」
|
||||
- ⚠️ 仅当用户主动要求撤销时才删除已创建任务
|
||||
|
||||
**阶段顺序**:
|
||||
```
|
||||
analysis → design → dev → review → testing → [待部署池] → released
|
||||
↑ /req deploy 批量推进
|
||||
```
|
||||
|
||||
**linkRole 到阶段的映射**:
|
||||
| linkRole | 所属阶段 |
|
||||
|----------|----------|
|
||||
| prd | analysis |
|
||||
| design | design |
|
||||
| implementation | dev |
|
||||
| code_review | review |
|
||||
| test | testing |
|
||||
| deploy (staging) | staging |
|
||||
| deploy (prod) | released |
|
||||
|
||||
## 会话恢复命令
|
||||
|
||||
### `/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 | 需求全生命周期 AI 开发管理优化
|
||||
状态: approved | 阶段: dev (开发)
|
||||
|
||||
📊 任务进度: 2/4 完成
|
||||
✅ #6051 【开发-后端】实现 advance_delivery_stage MCP 工具
|
||||
✅ #6052 【开发-后端】实现 create_stage_task 组合 MCP 工具
|
||||
🔄 #6053 【开发-Skill】req-commands 阶段 checklist 模板化 [in_progress]
|
||||
⬜ #6054 【开发-Skill】会话断点恢复机制 [todo]
|
||||
|
||||
▶ 建议操作:
|
||||
1. 继续任务 #6053(当前 in_progress)
|
||||
2. 执行 /req next 推进阶段
|
||||
3. 执行 /req phase 查看完整阶段视图
|
||||
```
|
||||
|
||||
**自动行为**:
|
||||
- 如果有 `in_progress` 任务,提示继续该任务
|
||||
- 如果当前阶段所有任务已完成,提示执行 `/req next`
|
||||
- 如果需求已 `archived`,告知用户无需操作
|
||||
|
||||
## 评审命令
|
||||
|
||||
### `/req review [REQ-ID]`
|
||||
提交评审。**前置条件**:必须有 PRD 文档。
|
||||
|
||||
**评审等待机制(强制)**:
|
||||
1. `submit_requirement(id)` → status 变为 pending
|
||||
2. 展示 PRD 要点摘要:
|
||||
```
|
||||
PRD 评审摘要
|
||||
─────────────────────
|
||||
标题: {需求标题}
|
||||
核心方案: {1-2句总结}
|
||||
验收标准: {N}项
|
||||
改动范围: {文件列表}
|
||||
```
|
||||
3. **AskUserQuestion**: "请确认 PRD 是否通过评审"
|
||||
- "通过评审" → `approve_requirement(id)`
|
||||
- "需要修改" → 回到编辑流程
|
||||
4. **⚠️ 禁止 AI 自动审批**,必须等待用户明确选择
|
||||
|
||||
### `/req review pass [REQ-ID]`
|
||||
评审通过。支持多人审批。参数:`--comment="审批意见"`
|
||||
|
||||
### `/req review reject [REQ-ID] [原因]`
|
||||
评审驳回。必须提供驳回原因。
|
||||
|
||||
### `/req review status [REQ-ID]`
|
||||
查看审批进度(多人审批时)。
|
||||
|
||||
## 开发命令
|
||||
|
||||
### `/req dev [REQ-ID]`
|
||||
启动开发,自动选择优先级最高的 todo 任务并开始计时。
|
||||
- 参数:`--task=<task-id>` 指定任务
|
||||
- 优先启动 `implementation` 角色任务
|
||||
- **自动设置** `delivery_stage = dev`(如尚未设置)
|
||||
|
||||
### `/req cr [REQ-ID]`
|
||||
代码评审。**前置条件**:开发任务完成。
|
||||
- 显示 Git diff 摘要
|
||||
- 生成代码评审检查清单
|
||||
- **自动设置** `delivery_stage = review`
|
||||
|
||||
### `/req test [REQ-ID]`
|
||||
启动测试。**前置条件**:代码评审通过。
|
||||
- 参数:`--skip-cr --reason="原因"` 跳过代码评审
|
||||
- **自动设置** `delivery_stage = testing`
|
||||
- **⭐ 遵循 `req-test-gate` v2 技能的 5 道门禁**
|
||||
|
||||
**执行逻辑(5-Gate 流程,详见 `req-test-gate` 技能)**:
|
||||
1. **Gate 1 前置条件**:CR 已通过 + 开发任务全部完成(不可跳过)
|
||||
2. **Gate 2 测试执行**:推断需求类型(code/skill/ops),分阶段验证
|
||||
- **code 类型四阶段**:
|
||||
- **2A 静态验证**:编译 + 单元测试 + 条件前端/iOS 测试
|
||||
- **2B 集成验证**:API 端点 + DB 约束 + 错误处理
|
||||
- **2C 冒烟测试**:Staging 环境健康检查 + 核心流程(已部署时)
|
||||
- **2D 原型符合性**:对比原型 HTML 的结构/字段/交互/状态(有原型时)
|
||||
- **skill**: 关键词一致性 + 规则无歧义 + 边界情况(至少 3 项)
|
||||
- **ops**: 部署命令可执行 + 健康检查
|
||||
3. **Gate 3 质量验证**:派遣 test-validator 子代理审查测试质量
|
||||
- code 类型:总是触发 | skill 类型:≥5 测试项时触发 | ops 类型:不触发
|
||||
- Critical 缺陷必须修复,Important 缺陷需 AskUserQuestion 确认
|
||||
4. **Gate 4 文档持久化(不可跳过)**:`create-and-attach` 将完整测试报告写入测试任务文档
|
||||
- 文档模板见 `req-test-gate` 技能的「最小必填模板」(含 2A-2D 阶段标记)
|
||||
- 必须包含:前置条件结果 + 测试执行表格 + 质量验证摘要 + 通过/失败结论
|
||||
- 无此文档 → `/req deploy` 前置检查会警告
|
||||
5. **Gate 5 回归贡献(code 类型)**:检查是否有 linkRole=regression 任务和用例文档
|
||||
- v2.0 过渡期为警告级别,不阻塞
|
||||
- 提醒补充回归测试用例到回归池
|
||||
|
||||
### `/req deploy [--project <name>] [--env <environment>]`
|
||||
**项目级批量部署**。收集所有待部署需求,一次构建部署。
|
||||
|
||||
- **这是项目级动作**,不是单需求操作
|
||||
- `--project` 默认为当前项目,`--env` 默认为 `staging`
|
||||
- 参数:`--platform=web|ios|android`
|
||||
- **⭐ 遵循 `req-test-gate` v2 的 Deploy Gates (DG1-DG6)**
|
||||
|
||||
**执行逻辑**:
|
||||
1. **前置检查(强制)**:
|
||||
- 对每个待部署需求,检查 testing 阶段任务是否有文档附件(`has_task_document`)
|
||||
- ✅ 有文档 → 继续
|
||||
- ⚠️ 无文档 → AskUserQuestion「测试任务 #XXXX 无测试记录文档,确认继续部署?」
|
||||
2. **收集待部署需求**:
|
||||
- `delivery_stage = testing` 且所有 test 任务 completed
|
||||
- 有 implementation 任务(排除纯运维/文档需求)
|
||||
3. **展示待部署列表** → `AskUserQuestion` 确认部署范围
|
||||
4. **创建部署批次任务**:
|
||||
- 标题:`【部署】{project} {date} ({N} requirements)`
|
||||
- 对每个选中需求:`link_tasks_to_requirement(role=deploy)`
|
||||
5. **Deploy Gates (DG1-DG6)**(详见 `req-test-gate/deploy-gates.md`):
|
||||
- **DG1 迁移检查(不可跳过)**:对比 migrations/ vs 数据库,有新 migration 先备份再执行
|
||||
- **DG2 Staging 部署**:构建镜像 + 部署到 singapore
|
||||
- **DG3 冒烟测试**:健康检查 + 登录 + 新 API 验证
|
||||
- **DG4 影响域回归**:根据 module-deps.json 运行对应回归套件(无套件时跳过)
|
||||
- **DG5 性能基线(推荐)**:关键 API 响应时间检查
|
||||
- **DG6 生产部署(不可跳过)**:部署 + 健康检查,失败立即回滚
|
||||
6. **部署后强制检查点**:
|
||||
- ✅ **部署文档创建**(必须):`create-and-attach` 到部署任务,包含 Deploy Gates 结果表格
|
||||
- ☑️ **截图验证**(可选):有 chrome-dev MCP → 执行截图;无 → 记录跳过
|
||||
7. **部署成功后**:
|
||||
- 所有关联需求 `advance_delivery_stage → released`
|
||||
- `complete_task(部署任务)`
|
||||
|
||||
**单需求兼容**:当仅 1 个需求待部署时,流程自动退化为单需求部署。
|
||||
|
||||
### `/req done [REQ-ID]`
|
||||
完成归档。参数:`--force` 强制归档。
|
||||
|
||||
**类型化归档门禁(强制)**:
|
||||
|
||||
1. `get_requirement_tasks(id)` → 获取所有关联任务
|
||||
2. **推断需求类型**(从 linkRole 集合判断):
|
||||
- **code**: 有 `implementation` 角色任务 → 代码需求
|
||||
- **skill**: 无 `implementation`,有 `prd`/`code_review`/`test` → Skill/文档需求
|
||||
- **ops**: 仅 `deploy` 角色任务 → 运维需求
|
||||
3. **按类型执行检查清单**:
|
||||
|
||||
| 检查项 | code | skill | ops |
|
||||
|--------|------|-------|-----|
|
||||
| delivery_stage = released | ✅ | - | - |
|
||||
| delivery_stage >= testing | - | ✅ | - |
|
||||
| deploy 任务已完成 | ✅ | - | ✅ |
|
||||
| 部署文档存在 | ✅ | - | - |
|
||||
| 所有关联任务已完成 | ✅ | ✅ | ✅ |
|
||||
|
||||
4. **检查结果处理**:
|
||||
- 全部通过 → 展示检查清单 + AskUserQuestion "确认归档?"
|
||||
- 有缺失 → 显示缺失项 + AskUserQuestion "是否强制归档?"
|
||||
- 用户确认 → 进入步骤 5
|
||||
5. **Git 提交(强制)**:
|
||||
- `git add` 本需求相关变更文件
|
||||
- `git commit -m "feat(skill): REQ-XXXX 需求标题"`(或 `fix`/`refactor` 等合适的 type)
|
||||
- `git push origin <current-branch>`
|
||||
- ⚠️ 提交前确认无敏感文件(.env、credentials 等)
|
||||
6. `archive_requirement(id)`
|
||||
7. 归档后生成生命周期总结,触发同步
|
||||
|
||||
### `/req regression [--module <name>] [--mode <mode>]`
|
||||
**运行回归测试**。系统级持续质量活动。
|
||||
|
||||
- `--module` 指定模块(okr/task/auth/...),不指定则按影响域推断
|
||||
- `--mode` 执行模式:`impact`(影响域)| `critical`(关键路径)| `full`(全量)
|
||||
- 默认模式:`impact`(根据最近变更推断影响域)
|
||||
|
||||
**执行逻辑**(详见 `req-test-gate/regression.md`):
|
||||
1. **确定范围**:
|
||||
- 指定 module → 直接运行该模块回归套件
|
||||
- 未指定 → `git diff --name-only` 获取变更 → 查 `module-deps.json` → 推断影响域
|
||||
2. **运行回归套件**:
|
||||
- 执行 `regression-suite/suites/` 下对应脚本
|
||||
- 记录每个用例的 PASS/FAIL 状态
|
||||
3. **回归判定**:
|
||||
- 对比上次运行结果
|
||||
- 上次 PASS + 本次 FAIL → 标记为「回归」
|
||||
4. **结果处理**:
|
||||
- 全部通过 → 展示通过率
|
||||
- 有回归 → AskUserQuestion「是否为回归项创建 bug 需求?」
|
||||
- 有新失败 → 展示失败列表,建议排查
|
||||
5. **报告输出**:
|
||||
```
|
||||
回归测试结果 - {module/all}
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
模式: {impact/critical/full}
|
||||
套件: {N} 个 | 用例: {M} 个
|
||||
✅ 通过: {P} | ❌ 失败: {F} | 🔴 回归: {R}
|
||||
```
|
||||
|
||||
**当前状态**:回归套件待初始化,首次运行会提示建立基线。
|
||||
|
||||
## 辅助命令
|
||||
|
||||
### `/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)
|
||||
☐ 【设计】数据模型设计 (linkRole: design) [可选]
|
||||
```
|
||||
|
||||
### dev(开发)
|
||||
```
|
||||
☐ 【开发-后端】{需求标题} (linkRole: implementation)
|
||||
☐ 【开发-前端】{需求标题} (linkRole: implementation) [可选]
|
||||
☐ 【开发-MCP】{需求标题} (linkRole: implementation) [可选]
|
||||
```
|
||||
|
||||
### review(代码评审)
|
||||
```
|
||||
☐ 【代码评审】{需求标题} (linkRole: code_review)
|
||||
```
|
||||
|
||||
### testing(测试)
|
||||
```
|
||||
☐ 【测试】单元测试: {需求标题} (linkRole: test)
|
||||
☐ 【测试】集成测试: {需求标题} (linkRole: test) [可选]
|
||||
```
|
||||
|
||||
**按需求类型的最低测试标准**:
|
||||
|
||||
| 需求类型 | 最低测试要求 |
|
||||
|----------|-------------|
|
||||
| **code** | `go test` 或前端测试通过 + API 验证 + 截图验证 |
|
||||
| **skill** | 关键词跨文件一致性 + 规则无歧义验证 + 边界情况检查(至少 3 项) |
|
||||
| **ops** | 部署命令可执行 + 健康检查通过 |
|
||||
|
||||
**skill 类型测试 checklist**(最低 3 项):
|
||||
```
|
||||
☐ 关键词一致性:grep 验证核心概念在所有相关 skill 文件中对齐
|
||||
☐ 规则无歧义:每条规则的触发条件和执行动作明确,无二义性
|
||||
☐ 边界情况:至少验证 1 个边界场景(如混合类型需求的分类)
|
||||
☐ 交叉引用:文件间的引用(如"见 xxx 技能")指向正确 [可选]
|
||||
```
|
||||
|
||||
### 部署(项目级,由 `/req deploy` 触发)
|
||||
|
||||
部署不再按单需求创建任务,而是通过 `/req deploy` 批量收集待部署需求:
|
||||
```
|
||||
testing 完成的需求 → 进入「待部署池」
|
||||
/req deploy → 创建批次任务:【部署】{project} {date} ({N} requirements)
|
||||
关联到所有选中需求 (linkRole: deploy)
|
||||
部署成功后批量推进 → released
|
||||
```
|
||||
|
||||
### `/req next` 执行流程(更新版)
|
||||
|
||||
1. `get_requirement(id)` → 获取 `delivery_stage`
|
||||
2. `get_requirement_tasks(id)` → 获取关联任务,收集 linkRole 集合
|
||||
3. **智能跳阶段检测**:检查目标阶段是否与 linkRole 匹配
|
||||
- 不匹配 → AskUserQuestion「建议跳过 {阶段},是否同意?」
|
||||
- 用户同意跳过 → 递归检测下一阶段
|
||||
- 用户拒绝 → 继续推进到该阶段
|
||||
4. **门禁检查**:`advance_delivery_stage(id, nextStage)` 自动检查
|
||||
- 通过 → 进入步骤 4.5
|
||||
- 未通过 → 显示阻塞任务,AskUserQuestion 确认 force(禁止自动 force)
|
||||
4.5. **⭐ 内容门禁检查(防空转)**:对关键阶段的已完成任务验证文档附件
|
||||
- **适用阶段**: review(CR 报告)、testing(测试结果)、staging(部署文档)
|
||||
- **检查逻辑**:
|
||||
```
|
||||
对当前阶段的每个 completed 任务:
|
||||
has_task_document(taskId) → 有文档?
|
||||
✅ 有 → get_task_document(taskId) → 检查质量:
|
||||
- review: ≥500字符 + 含 file:line 代码引用 + 含结论章节
|
||||
- testing: 含测试项表格 + 含通过/失败结论 + ≥200字符
|
||||
(详见 req-test-gate 技能 Gate 4 文档质量门禁)
|
||||
- staging: 含健康检查结果 + 含镜像/commit 信息
|
||||
❌ 无 → 阻止推进,提示「任务 #XXXX 缺少 {类型} 文档」
|
||||
```
|
||||
- **未通过处理**:AskUserQuestion「内容门禁未通过,选择操作」
|
||||
- 选项 A: "补充文档后重试"
|
||||
- 选项 B: "强制跳过(记录原因)" → 记录跳过原因到需求历史
|
||||
- **⚠️ 禁止 AI 自动跳过**,必须经过 AskUserQuestion
|
||||
5. **自动创建阶段任务**:`create_stage_task` 批量创建目标阶段建议任务
|
||||
- 展示已创建列表:「✅ 已创建: #XXXX {任务名}。如需撤销请说明」
|
||||
- 用户主动要求撤销时才删除
|
||||
|
||||
## 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` v2 5-Gate 流程: 前置检查 → 类型化测试(2A-2D) → test-validator 子代理 → `create-and-attach` 持久化 → 回归贡献检查 |
|
||||
| `/req deploy` | 前置检查 + Deploy Gates(DG1-DG6): 迁移→staging→冒烟→回归→性能→生产 + 部署文档 |
|
||||
| `/req regression` | `git diff` 影响域推断 + 运行回归套件 + 回归判定 + 可选创建 bug 需求 |
|
||||
| `/req done` | 类型推断 + 检查清单 + `AskUserQuestion` + `archive_requirement`(⚠️ 禁止直接调用 archive) |
|
||||
| `/req review` | `submit_requirement` |
|
||||
| `/req review pass` | `approve_requirement` |
|
||||
| `/req review reject` | `reject_requirement` |
|
||||
| `/req link` | `link_tasks_to_requirement` |
|
||||
|
||||
## 任务关联类型
|
||||
|
||||
| link_role | 说明 | 阶段前缀 | 进度权重 |
|
||||
|-----------|------|----------|----------|
|
||||
| prd | PRD 文档 | 【评审】 | 0.1 |
|
||||
| design | 技术设计 | 【评审】 | 0.05 |
|
||||
| implementation | 开发实现 | 【开发】 | 0.5 |
|
||||
| code_review | 代码评审 | 【代码评审】 | 0.05 |
|
||||
| test | 测试验证 | 【测试】 | 0.15 |
|
||||
| deploy | 部署发布 | 【部署】 | 0.1 |
|
||||
| regression | 回归用例 | 【回归】 | 0.0 |
|
||||
| documentation | 文档编写 | 【文档】 | 0.05 |
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "req-deploy-plugin",
|
||||
"description": "Plugin for req-deploy",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "req-deploy",
|
||||
"version": "1.0.0",
|
||||
"description": "需求部署技能。用于 Docker 镜像构建、Staging/Production 环境部署、API 验证、前端截图验证、部署文档创建。当用户执行 /req deploy 或需要部署需求时自动激活。",
|
||||
"triggerPatterns": [
|
||||
"部署",
|
||||
"deploy",
|
||||
"staging",
|
||||
"production",
|
||||
"镜像构建",
|
||||
"docker build",
|
||||
"Jenkins",
|
||||
"生产环境",
|
||||
"预发布"
|
||||
],
|
||||
"autoActivate": false,
|
||||
"hidden": false
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,115 +0,0 @@
|
||||
# 代码评审指南 (Code Review Guide)
|
||||
|
||||
代码评审是测试阶段的前置条件,确保代码质量在测试前得到验证。
|
||||
|
||||
## 评审时机
|
||||
|
||||
```
|
||||
开发完成 → 代码评审 → 测试
|
||||
↑ ↓
|
||||
└── 发现问题,修复后重新评审
|
||||
```
|
||||
|
||||
## 评审检查清单
|
||||
|
||||
### 1. 代码风格
|
||||
- [ ] 符合项目编码规范(Go/TypeScript)
|
||||
- [ ] 命名清晰有意义
|
||||
- [ ] 代码格式统一(已运行 lint/format)
|
||||
|
||||
### 2. 安全性
|
||||
- [ ] 无 SQL 注入风险
|
||||
- [ ] 无 XSS 漏洞
|
||||
- [ ] 无敏感信息硬编码(密码、密钥)
|
||||
- [ ] 权限检查完善
|
||||
|
||||
### 3. 错误处理
|
||||
- [ ] 异常捕获完善
|
||||
- [ ] 错误信息友好(不暴露内部细节)
|
||||
- [ ] 边界条件处理
|
||||
|
||||
### 4. 性能
|
||||
- [ ] 无 N+1 查询
|
||||
- [ ] 无不必要的循环/递归
|
||||
- [ ] 大数据量有分页处理
|
||||
|
||||
### 5. 日志与监控
|
||||
- [ ] 关键操作有日志
|
||||
- [ ] 日志级别适当
|
||||
- [ ] 无敏感信息输出到日志
|
||||
|
||||
### 6. 测试覆盖
|
||||
- [ ] 关键逻辑有单元测试
|
||||
- [ ] 测试用例有效
|
||||
|
||||
### 7. 文档
|
||||
- [ ] 复杂逻辑有注释
|
||||
- [ ] API 有文档说明
|
||||
|
||||
## 评审方式
|
||||
|
||||
| 方式 | 适用场景 |
|
||||
|------|----------|
|
||||
| 自评 (Self Review) | AI 开发的代码,Claude 自动检查 |
|
||||
| 他人评审 (Peer Review) | 团队协作,提交 PR 等待评审 |
|
||||
| 结对评审 (Pair Review) | 复杂功能,实时讨论 |
|
||||
|
||||
## 执行流程
|
||||
|
||||
### `/req cr` 命令执行步骤
|
||||
|
||||
1. **验证开发完成**
|
||||
```
|
||||
检查所有 implementation 任务状态 = completed
|
||||
```
|
||||
|
||||
2. **生成变更摘要**
|
||||
```bash
|
||||
git diff --stat HEAD~N # N = 开发期间的提交数
|
||||
git diff --name-only HEAD~N
|
||||
```
|
||||
|
||||
3. **显示检查清单**
|
||||
- 输出上述检查清单
|
||||
- 逐项确认或标记问题
|
||||
|
||||
4. **记录评审结果**
|
||||
- 通过:创建 code_review 任务并标记 completed
|
||||
- 不通过:列出问题,等待修复后重新评审
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Go 后端
|
||||
- 未检查 `error` 返回值
|
||||
- 缺少 `defer` 关闭资源
|
||||
- 并发访问未加锁
|
||||
|
||||
### TypeScript 前端
|
||||
- `any` 类型滥用
|
||||
- 缺少空值检查
|
||||
- 未处理异步错误
|
||||
|
||||
### 数据库
|
||||
- 缺少索引
|
||||
- 大事务未拆分
|
||||
- 未考虑并发更新
|
||||
|
||||
## 评审不通过时
|
||||
|
||||
```
|
||||
/req cr REQ-XXXX
|
||||
|
||||
→ 发现问题:
|
||||
⚠️ handlers/task_handler.go:245 - 缺少错误处理
|
||||
⚠️ pages/TaskList.tsx:88 - 存在 XSS 风险
|
||||
|
||||
→ 请修复后重新执行 /req cr
|
||||
```
|
||||
|
||||
## 跳过评审(紧急情况)
|
||||
|
||||
```bash
|
||||
/req test REQ-XXXX --skip-cr --reason="紧急生产修复"
|
||||
```
|
||||
|
||||
> 跳过评审需记录原因,事后补充评审。
|
||||
@@ -1,273 +0,0 @@
|
||||
# 部署指南
|
||||
|
||||
## 部署流程概览
|
||||
|
||||
```
|
||||
Staging 部署(手动) Production 部署(Jenkins)
|
||||
↓ ↓
|
||||
本地构建 :test 镜像 本地构建 :latest 镜像
|
||||
↓ ↓
|
||||
推送到 DockerHub 推送到 DockerHub
|
||||
↓ ↓
|
||||
显示部署命令 调用 Jenkins API
|
||||
↓ ↓
|
||||
用户手动执行 自动触发部署
|
||||
↓ ↓
|
||||
验证 API 轮询构建状态
|
||||
↓
|
||||
验证 API
|
||||
```
|
||||
|
||||
## 环境说明
|
||||
|
||||
| 环境 | 触发方式 | 镜像标签 | 用途 |
|
||||
|------|----------|----------|------|
|
||||
| staging | 手动 SSH | `:test` | 预发布测试 |
|
||||
| production | Jenkins API | `:latest` | 正式生产 |
|
||||
|
||||
## 镜像构建规范
|
||||
|
||||
> ⚠️ **重要**: 必须理解 Dockerfile target 和镜像标签的区别
|
||||
|
||||
### Dockerfile Target vs 镜像标签
|
||||
|
||||
| 概念 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| **Dockerfile Target** | 构建阶段,决定镜像内容 | `--target production`, `--target test` |
|
||||
| **镜像标签** | 版本标识,决定部署环境 | `:test`, `:latest` |
|
||||
|
||||
### 正确的构建方式
|
||||
|
||||
| 用途 | Dockerfile Target | 镜像标签 | 镜像大小 |
|
||||
|------|-------------------|----------|----------|
|
||||
| **Staging 部署** | `--target production` | `:test` | ~50MB |
|
||||
| **Production 部署** | `--target production` | `:latest` | ~50MB |
|
||||
| **运行单元测试** | `--target test` | 无需推送 | ~900MB+ |
|
||||
|
||||
### 常见错误
|
||||
|
||||
❌ **错误做法**:用 `--target test` 构建部署镜像
|
||||
```bash
|
||||
# 错误!这会生成 900MB+ 的镜像,包含测试框架和源代码
|
||||
docker buildx build --target test -t xxx:test ...
|
||||
```
|
||||
|
||||
✅ **正确做法**:用 `--target production` 构建部署镜像
|
||||
```bash
|
||||
# 正确!生成 ~50MB 的精简镜像,只包含二进制文件
|
||||
docker buildx build --target production -t xxx:test ...
|
||||
```
|
||||
|
||||
### Staging vs Production 镜像区别
|
||||
|
||||
两者都使用 `--target production` 构建,区别在于:
|
||||
|
||||
| 区别点 | Staging (`:test`) | Production (`:latest`) |
|
||||
|--------|-------------------|------------------------|
|
||||
| 镜像标签 | `:test` | `:latest` |
|
||||
| 前端 API URL | `staging.ai.pipexerp.com` | `ai.pipexerp.com` |
|
||||
| 后端代码 | 完全相同 | 完全相同 |
|
||||
| 部署服务器 | singapore | tools_ai_proj |
|
||||
|
||||
> **注意**: 不是把 staging 镜像部署到生产,而是测试通过后用生产 URL **重新构建** `:latest` 镜像
|
||||
|
||||
## Staging 部署
|
||||
|
||||
### 前置条件
|
||||
|
||||
> ⚠️ **必须完成本机测试才能部署 staging**
|
||||
|
||||
| 检查项 | 说明 |
|
||||
|--------|------|
|
||||
| 代码评审 | `/req cr` 已完成 |
|
||||
| 后端单元测试 | `go test ./... -v` 全部通过 |
|
||||
| **前端截图验证** | 使用 chrome-dev MCP 截图确认 UI 正确显示 |
|
||||
|
||||
如果本机测试未通过,将拒绝部署并提示:
|
||||
```
|
||||
→ ❌ 本机测试未完成,禁止部署到 staging
|
||||
→ 请先执行: /req test REQ-XXX
|
||||
```
|
||||
|
||||
### 命令格式
|
||||
|
||||
```bash
|
||||
/req deploy REQ-XXX --env staging [--service <service>]
|
||||
```
|
||||
|
||||
### 支持的服务
|
||||
|
||||
| 服务 | 说明 |
|
||||
|------|------|
|
||||
| `backend` | 后端 API 服务 |
|
||||
| `frontend` | 前端 Web 应用 |
|
||||
| `all` | 全部服务(默认) |
|
||||
|
||||
### 执行流程
|
||||
|
||||
1. **构建镜像**(本地执行)
|
||||
```bash
|
||||
# 后端
|
||||
docker buildx build --platform linux/amd64 \
|
||||
-f backend/Dockerfile --target production \
|
||||
-t saltthing123/ai-proj-backend:test --push backend/
|
||||
|
||||
# 前端(注意 API URL 配置)
|
||||
docker buildx build --platform linux/amd64 \
|
||||
-f frontend/Dockerfile.prod --target production \
|
||||
--build-arg REACT_APP_API_URL=https://staging.ai.pipexerp.com/api/v1 \
|
||||
--build-arg REACT_APP_API_BASE_URL=https://staging.ai.pipexerp.com/api/v1 \
|
||||
-t saltthing123/ai-proj-frontend:test --push frontend/
|
||||
```
|
||||
|
||||
2. **部署命令**(用户手动执行)
|
||||
```bash
|
||||
ssh singapore "cd /opt/ai-project-staging && \
|
||||
sudo docker-compose pull && \
|
||||
sudo docker-compose up -d"
|
||||
```
|
||||
|
||||
3. **验证**
|
||||
```bash
|
||||
curl -s https://staging.ai.pipexerp.com/api/v1/health | jq .
|
||||
```
|
||||
|
||||
## Production 部署
|
||||
|
||||
### 命令格式
|
||||
|
||||
```bash
|
||||
/req deploy REQ-XXX --env production [--service <service>]
|
||||
```
|
||||
|
||||
### 支持的服务
|
||||
|
||||
| 服务 | 镜像名 | Jenkins 参数 |
|
||||
|------|--------|--------------|
|
||||
| `backend` | saltthing123/ai-proj-backend | SERVICE=backend |
|
||||
| `frontend` | saltthing123/ai-proj-frontend | SERVICE=frontend |
|
||||
| `ios` | - | SERVICE=ios |
|
||||
| `android` | - | SERVICE=android |
|
||||
| `all` | 全部 | SERVICE=all(默认) |
|
||||
|
||||
### 执行流程
|
||||
|
||||
1. **构建镜像**(本地执行)
|
||||
```bash
|
||||
# 后端
|
||||
docker buildx build --platform linux/amd64 \
|
||||
-f backend/Dockerfile --target production \
|
||||
-t saltthing123/ai-proj-backend:latest --push backend/
|
||||
|
||||
# 前端
|
||||
docker buildx build --platform linux/amd64 \
|
||||
-f frontend/Dockerfile.prod --target production \
|
||||
--build-arg REACT_APP_API_URL=https://ai.pipexerp.com/api/v1 \
|
||||
--build-arg REACT_APP_API_BASE_URL=https://ai.pipexerp.com/api/v1 \
|
||||
-t saltthing123/ai-proj-frontend:latest --push frontend/
|
||||
```
|
||||
|
||||
2. **触发 Jenkins 部署**
|
||||
```bash
|
||||
source ~/.config/devops/credentials.env
|
||||
curl -X POST "$JENKINS_URL/job/ai-proj/buildWithParameters" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" \
|
||||
--data "SERVICE=backend&IMAGE_TAG=latest"
|
||||
```
|
||||
|
||||
3. **查看构建状态**
|
||||
```bash
|
||||
source ~/.config/devops/credentials.env
|
||||
curl -s "$JENKINS_URL/job/ai-proj/lastBuild/api/json" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" | jq '.result, .building'
|
||||
```
|
||||
|
||||
4. **验证**
|
||||
```bash
|
||||
curl -s https://ai.pipexerp.com/api/v1/health | jq .
|
||||
```
|
||||
|
||||
## 安全约束
|
||||
|
||||
- **禁止自动 SSH 部署到生产服务器**
|
||||
- 生产环境部署必须通过 Jenkins API 触发
|
||||
- Staging 部署命令只显示,由用户手动执行
|
||||
- 构建失败时必须显示错误原因和解决方案
|
||||
|
||||
## 项目配置
|
||||
|
||||
### AI-Proj
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| Jenkins Job | ai-proj |
|
||||
| Staging 服务器 | singapore |
|
||||
| Production 服务器 | tools_ai_proj |
|
||||
| DockerHub 用户 | saltthing123 |
|
||||
|
||||
### Coolbuy-Paas
|
||||
|
||||
| 配置项 | 值 |
|
||||
|--------|-----|
|
||||
| Jenkins Job | coolbuy-paas |
|
||||
| Staging 服务器 | fnos 测试环境 |
|
||||
| Production 服务器 | 39.106.88.83 |
|
||||
| DockerHub 用户 | saltthing123 |
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Docker 推送失败
|
||||
|
||||
**错误**: `push access denied`
|
||||
|
||||
**解决**:
|
||||
```bash
|
||||
docker login
|
||||
# 输入 Docker Hub 凭据
|
||||
```
|
||||
|
||||
### Jenkins 构建失败
|
||||
|
||||
**查看日志**:
|
||||
```bash
|
||||
source ~/.config/devops/credentials.env
|
||||
curl -s "$JENKINS_URL/job/ai-proj/lastBuild/consoleText" \
|
||||
-u "$JENKINS_USER:$JENKINS_TOKEN" | tail -100
|
||||
```
|
||||
|
||||
### 镜像架构不匹配
|
||||
|
||||
**错误**: `exec format error`
|
||||
|
||||
**原因**: 在 ARM64 (M1/M2 Mac) 构建的镜像部署到 AMD64 服务器
|
||||
|
||||
**解决**: 构建时必须指定 `--platform linux/amd64`
|
||||
|
||||
### 镜像体积异常大(900MB+)
|
||||
|
||||
**错误**: 构建的镜像超过 100MB
|
||||
|
||||
**原因**: 使用了错误的 Dockerfile target
|
||||
|
||||
**检查**:
|
||||
```bash
|
||||
# 查看镜像层大小
|
||||
docker history <image>:<tag> --no-trunc --format "{{.Size}}\t{{.CreatedBy}}" | head -10
|
||||
```
|
||||
|
||||
**常见原因**:
|
||||
| 层内容 | 大小 | 说明 |
|
||||
|--------|------|------|
|
||||
| `go mod download` | 600MB+ | Go 依赖包(不应出现在生产镜像) |
|
||||
| `ginkgo/gomega` | 200MB+ | 测试框架(不应出现在生产镜像) |
|
||||
| `COPY . .` | 100MB+ | 源代码(不应出现在生产镜像) |
|
||||
|
||||
**解决**: 确保使用 `--target production` 而不是 `--target test`
|
||||
|
||||
```bash
|
||||
# 错误
|
||||
docker buildx build --target test ...
|
||||
|
||||
# 正确
|
||||
docker buildx build --target production ...
|
||||
```
|
||||
@@ -1,55 +0,0 @@
|
||||
# Hook 自动同步机制
|
||||
|
||||
Hook 机制可在特定事件发生时自动触发同步,无需手动执行。
|
||||
|
||||
## 支持的 Hook 事件
|
||||
|
||||
| 事件 | 触发条件 | 自动执行操作 |
|
||||
|------|---------|-------------|
|
||||
| `requirement.created` | 创建新需求 | 同步需求到远程 |
|
||||
| `requirement.submitted` | 提交评审 | 发送评审通知 |
|
||||
| `requirement.approved` | 需求评审通过 | 同步需求 + 关联任务到远程 |
|
||||
| `requirement.archived` | 需求归档 | 最终同步 + 同步到思源笔记 + 发送通知 |
|
||||
| `task.completed` | 任务完成 | 同步任务状态到远程 |
|
||||
|
||||
## 配置 Hook
|
||||
|
||||
在 `.claude/settings.local.json` 中配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"requirement.approved": {
|
||||
"enabled": true,
|
||||
"actions": ["sync_requirement_to_remote", "sync_tasks_to_remote"]
|
||||
},
|
||||
"requirement.archived": {
|
||||
"enabled": true,
|
||||
"actions": ["sync_requirement_to_remote", "sync_to_siyuan", "send_notification"]
|
||||
},
|
||||
"task.completed": {
|
||||
"enabled": true,
|
||||
"actions": ["sync_task_to_remote"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 手动触发 Hook
|
||||
|
||||
```bash
|
||||
/req hook trigger requirement.approved REQ-2026-0010
|
||||
```
|
||||
|
||||
## 查看 Hook 执行历史
|
||||
|
||||
```bash
|
||||
/req hook history REQ-2026-0010
|
||||
```
|
||||
|
||||
## 禁用/启用 Hook
|
||||
|
||||
```bash
|
||||
/req hook disable REQ-2026-0010
|
||||
/req hook enable REQ-2026-0010
|
||||
```
|
||||
@@ -1,64 +0,0 @@
|
||||
# MCP 认证配置
|
||||
|
||||
## 环境选择原则
|
||||
|
||||
> 需求和任务的主数据源是**生产环境 (ai.pipexerp.com)**。
|
||||
> 所有需求创建、任务创建、查询、更新操作必须在生产环境执行。
|
||||
|
||||
| 环境 | 用途 | API 地址 |
|
||||
|------|------|----------|
|
||||
| **生产环境** | 需求创建、任务创建、数据管理 | https://ai.pipexerp.com/api/v1 |
|
||||
| 本地环境 | 代码开发调试、功能测试 | http://localhost:8080/api/v1 |
|
||||
|
||||
## MCP 配置
|
||||
|
||||
确保 `~/.claude/.mcp.json` 配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ai-proj": {
|
||||
"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_xxxxxxxx...",
|
||||
"SYNC_REMOTE_API_BASE": "https://ai.pipexerp.com/api/v1",
|
||||
"SYNC_REMOTE_API_KEY": "aiproj_pk_xxxxxxxx..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 认证方式
|
||||
|
||||
### PAT 秘钥(推荐)
|
||||
|
||||
- 格式: `aiproj_pk_` + 64 字符十六进制(共 74 字符)
|
||||
- 优势: 长期有效,无需频繁更新
|
||||
|
||||
### dev-quick-login(备选)
|
||||
|
||||
仅在 PAT 秘钥不可用时使用:
|
||||
|
||||
```bash
|
||||
curl -s -X POST "http://localhost:8080/api/v1/auth/dev-quick-login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username":"qiudl"}' | jq -r '.data.access_token'
|
||||
```
|
||||
|
||||
> JWT token 有效期 24 小时,日常使用推荐 PAT 秘钥。
|
||||
|
||||
## 验证 PAT 秘钥
|
||||
|
||||
```bash
|
||||
# 测试本地
|
||||
curl -s -H "X-API-Key: aiproj_pk_xxx..." \
|
||||
"http://localhost:8080/api/v1/tasks?limit=1" | jq '.success'
|
||||
|
||||
# 测试远程
|
||||
curl -s -H "Authorization: Bearer aiproj_pk_xxx..." \
|
||||
"https://ai.pipexerp.com/api/v1/tasks?limit=1" | jq '.success'
|
||||
```
|
||||
@@ -1,42 +0,0 @@
|
||||
# 通知与自动化配置
|
||||
|
||||
## 邮件通知
|
||||
|
||||
### 默认邮件组
|
||||
|
||||
| 收件人 |
|
||||
|--------|
|
||||
| qiudl@zhiyuncai.com |
|
||||
| fuxing@zhiyuncai.com |
|
||||
| haiqing@zhiyuncai.com |
|
||||
| wuweier@zhiyuncai.com |
|
||||
|
||||
### 通知类型
|
||||
|
||||
| 类型 | 触发时机 | 邮件主题 | 附件文档 |
|
||||
|------|----------|----------|----------|
|
||||
| `prd` | PRD完成 | [REQ-PRD] REQ-XXXX PRD文档已完成 | 01-PRD.md |
|
||||
| `dev` | 开发完成 | [REQ-开发] REQ-XXXX 开发完成 | 02-开发设计.md |
|
||||
| `test` | 测试完成 | [REQ-测试] REQ-XXXX 测试完成 | 03-测试报告.md |
|
||||
| `deploy` | 发布完成 | [REQ-发布] REQ-XXXX 已发布 | 04-发布记录.md |
|
||||
| `archive` | 归档 | [REQ-归档] REQ-XXXX 已归档 | 05-生命周期总结.md |
|
||||
|
||||
### 使用方式
|
||||
|
||||
```bash
|
||||
# 使用默认邮件组
|
||||
/req notify REQ-2026-0007 --type deploy
|
||||
|
||||
# 自定义收件人
|
||||
~/.claude/skills/req/notify.sh -r REQ-2026-0007 -t deploy -e "user1@example.com,user2@example.com"
|
||||
|
||||
# 不发送附件
|
||||
~/.claude/skills/req/notify.sh -r REQ-2026-0007 -t archive -n
|
||||
```
|
||||
|
||||
## 脚本文件
|
||||
|
||||
| 脚本 | 功能 | 位置 |
|
||||
|------|------|------|
|
||||
| notify.sh | 发送邮件通知 | ~/.claude/skills/req/ |
|
||||
| update-siyuan-release.sh | 更新思源笔记发布记录 | ~/.claude/skills/req/ |
|
||||
@@ -1,126 +0,0 @@
|
||||
# PRD 评审方法论
|
||||
|
||||
> 评审 PRD 是需求流程中的关键质量关卡。
|
||||
|
||||
## 评审流程
|
||||
|
||||
1. **结构完整性检查** - 检查 PRD 是否包含所有必要章节
|
||||
2. **需求清晰度评估** - 验证需求描述是否明确无歧义
|
||||
3. **技术可行性分析** - 评估技术方案是否可实现
|
||||
4. **数据模型验证** - 检查数据结构设计是否合理
|
||||
5. **API 设计审查** - 验证接口设计是否符合规范
|
||||
|
||||
## PRD 评审检查清单
|
||||
|
||||
### 一、结构完整性检查
|
||||
|
||||
| 检查项 | 必须 | 说明 |
|
||||
|--------|------|------|
|
||||
| 基本信息 | ✓ | 需求编号、标题、创建日期、作者 |
|
||||
| 需求背景 | ✓ | 为什么需要这个功能 |
|
||||
| 目标用户 | ✓ | 明确功能面向的用户群体 |
|
||||
| 功能描述 | ✓ | 详细的功能需求说明 |
|
||||
| 用户故事 | ○ | As a... I want... So that... |
|
||||
| 数据模型 | ✓ | 数据库表结构设计 |
|
||||
| API 设计 | ✓ | RESTful 接口定义 |
|
||||
| 页面原型 | ○ | 界面布局和交互说明 |
|
||||
| 非功能需求 | ○ | 性能、安全、可用性要求 |
|
||||
| 验收标准 | ✓ | 明确的功能验收条件 |
|
||||
|
||||
> ✓ = 必须包含, ○ = 建议包含
|
||||
|
||||
### 二、需求清晰度评估(SMART 原则)
|
||||
|
||||
| 原则 | 检查点 | 示例 |
|
||||
|------|--------|------|
|
||||
| **S**pecific | 需求描述是否具体明确 | ❌ "支持搜索" → ✅ "支持按需求编号、标题模糊搜索" |
|
||||
| **M**easurable | 是否有量化指标 | ❌ "快速响应" → ✅ "响应时间 < 200ms" |
|
||||
| **A**chievable | 技术上是否可行 | 评估现有技术栈能否支持 |
|
||||
| **R**elevant | 是否与业务目标相关 | 功能是否解决实际问题 |
|
||||
| **T**ime-bound | 是否有明确的时间范围 | 开发周期、上线日期 |
|
||||
|
||||
### 三、技术可行性分析
|
||||
|
||||
| 检查维度 | 评估内容 |
|
||||
|----------|----------|
|
||||
| 技术栈兼容性 | 现有技术栈是否支持所需功能 |
|
||||
| 系统架构影响 | 是否需要修改现有架构 |
|
||||
| 第三方依赖 | 是否引入新的外部依赖 |
|
||||
| 性能影响 | 对系统性能的潜在影响 |
|
||||
| 安全考量 | 是否存在安全风险 |
|
||||
| 数据迁移 | 是否需要数据迁移方案 |
|
||||
|
||||
### 四、数据模型验证
|
||||
|
||||
| 检查项 | 说明 |
|
||||
|--------|------|
|
||||
| 表结构设计 | 字段类型、约束、索引是否合理 |
|
||||
| 关联关系 | 外键、多对多关系是否正确 |
|
||||
| 命名规范 | 表名、字段名是否符合项目规范 |
|
||||
| 扩展性 | 是否预留扩展字段 |
|
||||
| 数据量预估 | 数据增长预估和存储方案 |
|
||||
| 查询性能 | 常用查询是否有索引支持 |
|
||||
|
||||
### 五、API 设计审查
|
||||
|
||||
| 检查项 | 标准 |
|
||||
|--------|------|
|
||||
| RESTful 规范 | URL 使用名词、HTTP 方法语义正确 |
|
||||
| 响应格式 | 统一的响应结构 `{success, data, message}` |
|
||||
| 错误处理 | 明确的错误码和错误信息 |
|
||||
| 分页设计 | 列表接口支持分页 `?page=1&page_size=20` |
|
||||
| 参数验证 | 必填参数、类型、范围说明 |
|
||||
| 版本控制 | API 路径包含版本 `/api/v1/...` |
|
||||
|
||||
## 评审意见模板
|
||||
|
||||
### 通过模板
|
||||
|
||||
```
|
||||
✅ PRD 评审通过
|
||||
|
||||
【评审结论】
|
||||
PRD 文档结构完整,需求描述清晰,技术方案可行,建议批准进入开发阶段。
|
||||
|
||||
【肯定之处】
|
||||
- 需求背景阐述清晰
|
||||
- 数据模型设计合理
|
||||
- API 接口规范
|
||||
|
||||
【建议改进】(非阻塞)
|
||||
- 建议补充性能测试用例
|
||||
- 建议增加边界条件说明
|
||||
|
||||
【评审人】xxx
|
||||
【评审时间】2026-01-24 10:00
|
||||
```
|
||||
|
||||
### 驳回模板
|
||||
|
||||
```
|
||||
❌ PRD 评审驳回
|
||||
|
||||
【驳回原因】
|
||||
1. 数据模型缺少索引设计
|
||||
2. API 接口缺少错误处理说明
|
||||
3. 搜索功能需求描述模糊
|
||||
|
||||
【修改要求】
|
||||
□ 补充数据表索引设计
|
||||
□ 明确 API 错误码定义
|
||||
□ 细化搜索功能的具体实现方式
|
||||
|
||||
【驳回人】xxx
|
||||
【驳回时间】2026-01-24 10:00
|
||||
```
|
||||
|
||||
## 常见驳回原因
|
||||
|
||||
| 类别 | 常见问题 | 改进建议 |
|
||||
|------|----------|----------|
|
||||
| 结构缺失 | 缺少数据模型或 API 设计 | 补充完整的技术设计章节 |
|
||||
| 需求模糊 | 功能描述不够具体 | 按 SMART 原则重新描述 |
|
||||
| 边界不清 | 缺少边界条件和异常处理 | 补充边界条件和错误场景 |
|
||||
| 设计缺陷 | 数据模型或 API 设计不合理 | 重新设计并说明理由 |
|
||||
| 范围过大 | 需求范围过大难以实现 | 拆分为多个小需求 |
|
||||
| 验收不明 | 缺少验收标准 | 补充可验证的验收条件 |
|
||||
@@ -1,50 +0,0 @@
|
||||
# 思源笔记集成
|
||||
|
||||
需求的 5 阶段文档统一存储到思源笔记中。
|
||||
|
||||
## 文档结构
|
||||
|
||||
```
|
||||
需求管理/
|
||||
└── REQ-2026-XXXX/
|
||||
├── 01-PRD.md # 产品需求文档
|
||||
├── 02-开发设计.md # 开发技术文档
|
||||
├── 03-测试报告.md # 测试验收报告
|
||||
├── 04-发布记录.md # CI/CD发布记录
|
||||
└── 05-生命周期总结.md # 需求归档总结
|
||||
```
|
||||
|
||||
## 同步命令
|
||||
|
||||
```bash
|
||||
/req sync-siyuan REQ-2026-0007
|
||||
```
|
||||
|
||||
## 自动同步时机
|
||||
|
||||
| 阶段 | 触发命令 | 同步文档 |
|
||||
|------|---------|---------|
|
||||
| PRD 完成 | `/req review` | 01-PRD.md |
|
||||
| 开发完成 | `/req test` | 02-开发设计.md |
|
||||
| 测试完成 | `/req deploy` | 03-测试报告.md |
|
||||
| 发布完成 | 发布任务完成 | 04-发布记录.md |
|
||||
| 归档完成 | `/req done` | 05-生命周期总结.md (全量同步) |
|
||||
|
||||
## MCP 工具调用
|
||||
|
||||
```python
|
||||
# 创建文档
|
||||
mcp__siyuan__createDocWithMd(
|
||||
notebook="需求管理",
|
||||
path="/REQ-2026-0007/01-PRD",
|
||||
markdown=prd_content
|
||||
)
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
环境变量(可选):
|
||||
```bash
|
||||
export SIYUAN_URL="http://100.118.62.18:6806"
|
||||
export SIYUAN_TOKEN="your-token"
|
||||
```
|
||||
@@ -376,9 +376,185 @@ ai-proj req tasks --id <id> # 查看关联任务
|
||||
|
||||
**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]`
|
||||
|
||||
## 相关技能
|
||||
|
||||
| 技能 | 用途 |
|
||||
|------|------|
|
||||
| `req-prd` | PRD 文档编写 + 评审方法论 |
|
||||
| `dev-test` | 测试 + 质量门禁 |
|
||||
| `req-test-gate` | 测试 5-Gate + Deploy Gates |
|
||||
| `req-dev` | PRD 到代码转换、开发计划 |
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
# 测试环境流程指南
|
||||
|
||||
> 测试必须按照以下环境顺序依次进行,每个环境通过后才能进入下一个环境。
|
||||
|
||||
## 测试环境流程
|
||||
|
||||
```
|
||||
[1] 本机环境 ─── 通过 ──→ [2] 预发布环境 ─── 通过 ──→ [3] 生产环境
|
||||
│ │ │
|
||||
↓ 失败 ↓ 失败 ↓ 失败
|
||||
修复并重测 回到步骤[1] 回到步骤[1]
|
||||
```
|
||||
|
||||
## 项目环境配置表
|
||||
|
||||
| 项目 | 本机环境 | 预发布环境 | 生产环境 |
|
||||
|------|---------|-----------|---------|
|
||||
| ai-proj | localhost:3000/8080 | staging.ai.pipexerp.com | ai.pipexerp.com |
|
||||
| coolbuy-paas | localhost | fnos 测试环境 | 39.106.88.83:8888 |
|
||||
| coolbuy-platform | localhost | fnos 测试环境 | 生产服务器 |
|
||||
|
||||
## 第一阶段:本机测试环境
|
||||
|
||||
> ⚠️ **关键约束**:本机测试必须全部通过,才能部署到 staging 环境。
|
||||
|
||||
**测试内容**:
|
||||
- 单元测试 - 测试单个函数/方法,Mock 外部依赖
|
||||
- 集成测试 - 测试模块间交互,使用测试数据库
|
||||
- 功能验证 - 验证功能逻辑正确性
|
||||
- **前端截图验证** - 使用 chrome-dev MCP 截图确认 UI 显示正确
|
||||
|
||||
### 后端测试
|
||||
|
||||
```bash
|
||||
# Go 后端单元测试
|
||||
go test ./... -v
|
||||
|
||||
# 指定模块测试
|
||||
go test ./backend/handlers/... -v
|
||||
go test ./backend/services/... -v
|
||||
```
|
||||
|
||||
### 前端截图验证(⚠️ 必须步骤)
|
||||
|
||||
> **重要**:前端改动必须通过截图验证,不能只测后端 API。这一步经常被忽略,导致功能未正确显示。
|
||||
|
||||
**验证流程**:
|
||||
|
||||
1. **确保本机服务运行**
|
||||
```bash
|
||||
# 终端1:后端
|
||||
cd backend && go run main.go
|
||||
|
||||
# 终端2:前端
|
||||
cd frontend && npm start
|
||||
```
|
||||
|
||||
2. **使用 chrome-dev MCP 截图验证**
|
||||
```python
|
||||
# 步骤1:导航到目标页面
|
||||
mcp__chrome-dev__navigate_page(url="http://localhost:3000/requirements/686")
|
||||
|
||||
# 步骤2:等待页面加载完成(可选)
|
||||
mcp__chrome-dev__wait_for(selector=".requirement-detail")
|
||||
|
||||
# 步骤3:截图
|
||||
mcp__chrome-dev__take_screenshot()
|
||||
|
||||
# 步骤4:检查截图中功能是否正确显示
|
||||
# - 新增的列/字段是否显示
|
||||
# - 样式是否正确
|
||||
# - 数据是否正确渲染
|
||||
```
|
||||
|
||||
3. **常见验证场景**
|
||||
| 改动类型 | 验证页面 | 检查项 |
|
||||
|---------|---------|--------|
|
||||
| 列表新增列 | 列表页面 | 新列是否显示、数据是否正确 |
|
||||
| 表单新增字段 | 表单页面 | 字段是否显示、能否正常输入 |
|
||||
| 样式调整 | 相关页面 | 样式是否生效、布局是否正确 |
|
||||
| 权限控制 | 相关页面 | 按钮/菜单是否正确显示/隐藏 |
|
||||
|
||||
4. **截图保存**
|
||||
- 截图应保存到测试任务文档中作为验证记录
|
||||
- 命名规范:`REQ-XXXXX-本机测试-功能名称.png`
|
||||
|
||||
### 前端截图验证示例
|
||||
|
||||
```
|
||||
/req test REQ-20260125-0002
|
||||
|
||||
→ 检查代码评审... ✓ 已完成
|
||||
→ 验证开发任务... ✓ 已完成
|
||||
|
||||
=== 本机测试阶段 ===
|
||||
|
||||
1. 后端单元测试
|
||||
→ go test ./backend/handlers/requirement_handler_test.go -v
|
||||
→ ✓ 3/3 测试通过
|
||||
|
||||
2. 前端截图验证
|
||||
→ 启动 chrome-dev MCP...
|
||||
→ 导航到: http://localhost:3000/requirements/687
|
||||
→ 截图验证...
|
||||
→ ✓ 任务ID列正确显示 (#5284 格式)
|
||||
→ ✓ 列宽度和样式正确
|
||||
→ 截图已保存
|
||||
|
||||
=== 本机测试通过 ===
|
||||
→ 可以执行: /req deploy REQ-20260125-0002 --env staging
|
||||
```
|
||||
|
||||
### 通过标准
|
||||
|
||||
- [ ] 所有后端单元测试通过
|
||||
- [ ] **前端截图验证通过**(有前端改动时必须)
|
||||
- [ ] 功能在本地环境正常运行
|
||||
- [ ] 无控制台错误
|
||||
- [ ] 截图已保存到测试文档
|
||||
|
||||
### 跳过前端验证
|
||||
|
||||
仅当改动不涉及前端时,可使用 `--backend-only` 参数:
|
||||
|
||||
```bash
|
||||
/req test REQ-XXXXX --backend-only
|
||||
```
|
||||
|
||||
## 第二阶段:预发布环境
|
||||
|
||||
**测试内容**:
|
||||
- E2E 测试 - 测试完整用户流程
|
||||
- 跨浏览器测试 - Chrome、Firefox、Safari
|
||||
- 性能测试 - 页面加载时间、API 响应时间
|
||||
|
||||
**通过标准**:
|
||||
- [ ] 功能在预发布环境正常运行
|
||||
- [ ] 与生产环境配置一致
|
||||
- [ ] 无跨环境兼容性问题
|
||||
|
||||
## 第三阶段:生产环境
|
||||
|
||||
**测试内容**:
|
||||
- UAT 验收 - 用户验收测试
|
||||
- 冒烟测试 - 核心功能快速验证
|
||||
- 回归测试 - 确保未破坏现有功能
|
||||
|
||||
**通过标准**:
|
||||
- [ ] 功能在生产环境正常运行
|
||||
- [ ] 用户验收通过
|
||||
- [ ] 无生产环境特有问题
|
||||
|
||||
## API 验证清单
|
||||
|
||||
```bash
|
||||
# 1. 本机环境
|
||||
curl -s "http://localhost:8080/api/v1/requirements?search=REQ-2026" \
|
||||
-H "Authorization: Bearer $TOKEN" | jq '.data | length'
|
||||
|
||||
# 2. 预发布环境
|
||||
curl -s "https://staging.ai.pipexerp.com/api/v1/requirements?search=REQ-2026" \
|
||||
-H "X-API-Key: $SYNC_REMOTE_API_KEY" | jq '.data | length'
|
||||
|
||||
# 3. 生产环境
|
||||
curl -s "https://ai.pipexerp.com/api/v1/requirements?search=REQ-2026" \
|
||||
-H "X-API-Key: $SYNC_REMOTE_API_KEY" | jq '.data | length'
|
||||
```
|
||||
|
||||
## 测试失败处理
|
||||
|
||||
| 失败阶段 | 处理方式 |
|
||||
|---------|---------|
|
||||
| 本机测试 | 修复代码,重新运行本机测试 |
|
||||
| 预发布测试 | 修复代码,重新从本机测试开始 |
|
||||
| 生产环境测试 | 修复代码,重新从本机测试开始 |
|
||||
|
||||
> 任何阶段测试失败,修复后必须从本机测试环境重新开始。
|
||||
@@ -1,120 +0,0 @@
|
||||
# 完整开发工作流示例
|
||||
|
||||
以「酷采3.0 标签管理模块」为例的完整需求生命周期。
|
||||
|
||||
## 第一步:创建需求
|
||||
|
||||
```bash
|
||||
/req new 酷采3.0 商品标签管理模块
|
||||
```
|
||||
|
||||
执行:`mcp__ai-proj__create_requirement` → 自动分配 display_id(如 REQ-2026-0006)
|
||||
|
||||
## 第二步:编写 PRD 文档
|
||||
|
||||
调用 `req-prd` 技能:
|
||||
1. 创建 PRD 任务并关联到需求
|
||||
2. 调用 `mcp__ai-proj__create-and-attach` 写入 PRD 文档
|
||||
|
||||
## 第三步:创建开发子任务
|
||||
|
||||
```python
|
||||
# 创建子任务
|
||||
mcp__ai-proj__create_subtask(parentId=PRD任务ID, title="后端:数据模型设计")
|
||||
mcp__ai-proj__create_subtask(parentId=PRD任务ID, title="后端:Store/Biz实现")
|
||||
mcp__ai-proj__create_subtask(parentId=PRD任务ID, title="后端:API Handler实现")
|
||||
mcp__ai-proj__create_subtask(parentId=PRD任务ID, title="前端:页面开发")
|
||||
|
||||
# 批量关联到需求
|
||||
mcp__ai-proj__link_tasks_to_requirement(requirementId=需求ID, taskIds=[...])
|
||||
```
|
||||
|
||||
## 第四步:提交并审批需求
|
||||
|
||||
```bash
|
||||
/req review # draft → pending
|
||||
/req review pass # pending → approved
|
||||
```
|
||||
|
||||
## 第五步:执行开发任务
|
||||
|
||||
```bash
|
||||
/req dev REQ-2026-0006
|
||||
```
|
||||
|
||||
按分层架构开发:Model → Store → Biz → Handler → Router
|
||||
|
||||
## 第六步:代码评审
|
||||
|
||||
```bash
|
||||
/req cr REQ-2026-0006
|
||||
```
|
||||
|
||||
开发完成后必须进行代码评审,评审通过后才能进入测试。
|
||||
|
||||
## 第七步:创建测试任务
|
||||
|
||||
```python
|
||||
mcp__ai-proj__create_subtask(parentId=测试父任务, title="后端:单元测试")
|
||||
mcp__ai-proj__create_subtask(parentId=测试父任务, title="后端:集成测试")
|
||||
mcp__ai-proj__create_subtask(parentId=测试父任务, title="E2E:端到端测试")
|
||||
mcp__ai-proj__create_subtask(parentId=测试父任务, title="UAT:用户验收测试")
|
||||
```
|
||||
|
||||
## 第八步:执行测试
|
||||
|
||||
```bash
|
||||
/req test REQ-2026-0006
|
||||
```
|
||||
|
||||
按环境顺序:本机 → 预发布 → 生产
|
||||
|
||||
## 第九步:CI/CD 发布
|
||||
|
||||
```bash
|
||||
/req deploy REQ-2026-0006 --env staging
|
||||
```
|
||||
|
||||
## 第十步:完成归档
|
||||
|
||||
```bash
|
||||
/req done REQ-2026-0006
|
||||
```
|
||||
|
||||
自动生成需求生命周期总结文档,归档需求。
|
||||
|
||||
---
|
||||
|
||||
## 标准任务结构
|
||||
|
||||
```
|
||||
需求: REQ-2026-XXXX
|
||||
├── PRD 任务 (父任务,包含 PRD 文档)
|
||||
│ ├── 后端:数据模型设计 (implementation)
|
||||
│ ├── 后端:业务层实现 (implementation)
|
||||
│ ├── 后端:API 实现 (implementation)
|
||||
│ └── 前端:页面开发 (implementation)
|
||||
│
|
||||
├── 代码评审任务 (code_review) ← 必须步骤
|
||||
│
|
||||
├── 测试任务 (父任务)
|
||||
│ ├── 单元测试 (test)
|
||||
│ ├── 集成测试 (test)
|
||||
│ ├── E2E测试 (test)
|
||||
│ └── UAT验收 (test, 包含测试报告)
|
||||
│
|
||||
└── 发布任务 (父任务,包含发布记录)
|
||||
├── Docker 镜像构建 (deploy)
|
||||
├── 前端资源构建 (deploy)
|
||||
└── 部署到环境 (deploy)
|
||||
```
|
||||
|
||||
## 5 阶段文档
|
||||
|
||||
| 序号 | 文档 | 阶段 |
|
||||
|------|------|------|
|
||||
| 01 | PRD | 需求定义 |
|
||||
| 02 | 开发设计 | 开发实现 |
|
||||
| 03 | 测试报告 | 测试验收 |
|
||||
| 04 | 发布记录 | CI/CD部署 |
|
||||
| 05 | 生命周期总结 | 归档 |
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: req-prd
|
||||
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划。当用户提到产品设计、PRD、需求文档、功能规划、用户故事相关任务时自动激活。
|
||||
description: 产品设计与需求管理。用于 PRD 文档编写、需求分析、用户故事创建、功能设计和原型规划、PRD 评审。当用户提到产品设计、PRD、需求文档、功能规划、用户故事、PRD 评审相关任务时自动激活。
|
||||
---
|
||||
|
||||
# 产品需求设计 Skill (req-prd)
|
||||
@@ -657,3 +657,114 @@ mcp__ai-proj__export_task_document_to_file
|
||||
- 数据安全分级
|
||||
- 敏感操作审计
|
||||
- 权限最小化原则
|
||||
|
||||
---
|
||||
|
||||
## PRD 评审方法论
|
||||
|
||||
PRD 评审是需求流程的关键质量关卡。
|
||||
|
||||
### 评审流程
|
||||
|
||||
```
|
||||
PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据模型 → API 审查 → 结论
|
||||
```
|
||||
|
||||
### 结构完整性检查
|
||||
|
||||
| 检查项 | 必须 | 说明 |
|
||||
|--------|:----:|------|
|
||||
| 基本信息 | ✓ | 编号、标题、日期、作者 |
|
||||
| 需求背景 | ✓ | 为什么需要这个功能 |
|
||||
| 目标用户 | ✓ | 面向的用户群体 |
|
||||
| 功能描述 | ✓ | 详细功能需求 |
|
||||
| 数据模型 | ✓ | 数据库表结构 |
|
||||
| API 设计 | ✓ | RESTful 接口 |
|
||||
| 验收标准 | ✓ | 验收条件 |
|
||||
| 用户故事 | ○ | As a... I want... |
|
||||
| 页面原型 | ○ | 界面布局 |
|
||||
| 非功能需求 | ○ | 性能、安全 |
|
||||
|
||||
### 需求清晰度(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 不合理 | 重新设计 |
|
||||
| 范围过大 | 难以实现 | 拆分为多需求 |
|
||||
| 验收不明 | 缺验收标准 | 补充验收条件 |
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "req-review-plugin",
|
||||
"description": "PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
---
|
||||
name: req-review
|
||||
description: PRD 评审方法论。用于需求评审、PRD 文档审查、评审意见编写。当执行 /req review 或需要评审 PRD 文档时使用。
|
||||
---
|
||||
|
||||
# PRD 评审方法论
|
||||
|
||||
PRD 评审是需求流程的关键质量关卡。
|
||||
|
||||
## 评审流程
|
||||
|
||||
```
|
||||
PRD 提交 → 结构检查 → 清晰度评估 → 技术可行性 → 数据模型 → API 审查 → 结论
|
||||
```
|
||||
|
||||
## 结构完整性检查
|
||||
|
||||
| 检查项 | 必须 | 说明 |
|
||||
|--------|:----:|------|
|
||||
| 基本信息 | ✓ | 编号、标题、日期、作者 |
|
||||
| 需求背景 | ✓ | 为什么需要这个功能 |
|
||||
| 目标用户 | ✓ | 面向的用户群体 |
|
||||
| 功能描述 | ✓ | 详细功能需求 |
|
||||
| 数据模型 | ✓ | 数据库表结构 |
|
||||
| API 设计 | ✓ | RESTful 接口 |
|
||||
| 验收标准 | ✓ | 验收条件 |
|
||||
| 用户故事 | ○ | As a... I want... |
|
||||
| 页面原型 | ○ | 界面布局 |
|
||||
| 非功能需求 | ○ | 性能、安全 |
|
||||
|
||||
## 需求清晰度(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 不合理 | 重新设计 |
|
||||
| 范围过大 | 难以实现 | 拆分为多需求 |
|
||||
| 验收不明 | 缺验收标准 | 补充验收条件 |
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "req-workflow-plugin",
|
||||
"description": "需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
---
|
||||
name: req-workflow
|
||||
description: 需求完整工作流。用于从创建到归档的完整流程、Hook 自动同步、测试环境流程。当需要了解需求完整生命周期或同步策略时使用。
|
||||
---
|
||||
|
||||
# 需求完整工作流
|
||||
|
||||
从 PRD 到归档的完整流程。
|
||||
|
||||
## 需求创建环境选择
|
||||
|
||||
> **重要**:正式需求应直接在**生产环境** (`mcp__ai-proj-prod__*`) 创建。
|
||||
> 仅在功能测试、流程验证时使用开发环境 (`mcp__ai-proj-dev__*`)。
|
||||
> 如果在开发环境创建了需求后同步到生产,`due_date`、`reviewer_id`、`allow_self_approve` 等字段会丢失,需手动补充。
|
||||
|
||||
## 完整流程概览(阶段化)
|
||||
|
||||
```
|
||||
1. /req new → 创建需求 (draft)
|
||||
2. req-prd 技能 → 编写 PRD(创建【评审】PRD 任务)
|
||||
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-dev 技能 → 编写开发文档
|
||||
8. /req next → 推进到 review 阶段
|
||||
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 → 部署生产(创建【部署】任务, delivery_stage=released)
|
||||
16. /req done → 归档 (archived)
|
||||
```
|
||||
|
||||
**每个阶段都有明确的任务、检查点和交付物,防止遗漏。**
|
||||
|
||||
## 5 阶段文档
|
||||
|
||||
| 阶段 | 文档名 | 技能 |
|
||||
|------|--------|------|
|
||||
| PRD | 01-PRD.md | `req-prd` |
|
||||
| 开发 | 02-开发设计.md | `req-dev` |
|
||||
| 测试 | 03-测试报告.md | 自动生成 |
|
||||
| 发布 | 04-发布记录.md | 自动生成 |
|
||||
| 归档 | 05-生命周期总结.md | 自动生成 |
|
||||
|
||||
## 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 | ✅ | 正常同步 |
|
||||
| project_id | ✅ | 正常同步 |
|
||||
| **due_date** | ❌ | **不会同步**,需手动通过 REST API 在目标环境补充 |
|
||||
| reviewer_id | ❌ | 不会同步 |
|
||||
| allow_self_approve | ❌ | 不会同步 |
|
||||
|
||||
> **经验教训**(2026-02-20):`sync_requirement_to_remote` 不同步 `due_date` 字段。同步后务必在目标环境验证并手动补充缺失字段。
|
||||
|
||||
## 测试环境流程
|
||||
|
||||
**必须按顺序执行,任何阶段失败后从本机重新开始**:
|
||||
|
||||
```
|
||||
[本机] → 通过 → [预发布] → 通过 → [生产]
|
||||
↑ │ │
|
||||
└─────────────────┴──── 失败 ────┘
|
||||
```
|
||||
|
||||
| 环境 | 用途 | 验证方式 |
|
||||
|------|------|----------|
|
||||
| 本机 | 开发调试 | `go test ./...` |
|
||||
| 预发布 | 集成测试 | API 验证 |
|
||||
| 生产 | 最终验收 | API + 功能验证 |
|
||||
|
||||
## 任务关联规范
|
||||
|
||||
创建任务时设置 `link_role` 并加阶段前缀:
|
||||
|
||||
| link_role | 阶段前缀 | 所属阶段 | 权重 |
|
||||
|-----------|----------|----------|------|
|
||||
| prd | 【评审】 | analysis | 10% |
|
||||
| design | 【评审】 | design | 5% |
|
||||
| implementation | 【开发】 | dev | 50% |
|
||||
| code_review | 【代码评审】 | review | 5% |
|
||||
| test | 【测试】 | testing | 15% |
|
||||
| deploy | 【部署】 | staging/released | 10% |
|
||||
| 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)
|
||||
└── 【验收】功能验收确认 (linkRole: documentation)
|
||||
```
|
||||
|
||||
**命名规则**:所有任务标题必须以阶段前缀开头(如【评审】、【开发】、【部署】)。
|
||||
|
||||
## 环境配置
|
||||
|
||||
**双环境 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>`
|
||||
|
||||
默认收件人:项目邮件组(见项目配置)
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"name": "requirement-plugin",
|
||||
"description": "[已废弃] 需求撰写功能已合并到 req-plugin。请使用 /req 命令。",
|
||||
"version": "2.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
name: requirement
|
||||
description: "[已废弃] 请使用 /req 命令。需求撰写功能已合并到 req 技能中。"
|
||||
arguments: <subcommand> [args]
|
||||
---
|
||||
|
||||
# Requirement 技能 - 已合并到 req
|
||||
|
||||
> **此技能已废弃。** 所有需求撰写命令已合并到 `req` 技能中。
|
||||
|
||||
## 命令迁移对照
|
||||
|
||||
| 原命令 | 新命令 | 说明 |
|
||||
|--------|--------|------|
|
||||
| `/requirement new` | `/req new` | 对话式创建需求(仅创建草稿) |
|
||||
| `/requirement draft <描述>` | `/req draft <描述>` | 快速生成需求草稿 |
|
||||
| `/requirement edit <ID>` | `/req edit <ID>` | 编辑需求内容 |
|
||||
| `/requirement review <ID>` | `/req check <ID>` | 需求完整性检查 |
|
||||
| `/requirement split <ID>` | `/req split <ID>` | 拆分为开发任务 |
|
||||
| `/requirement history <ID>` | `/req history <ID>` | 查看变更历史 |
|
||||
| `/requirement compare <ID>` | `/req compare <ID>` | 版本对比 |
|
||||
| `/requirement list` | `/req` 或 `/req list` | 列出需求 |
|
||||
|
||||
## 重要变更
|
||||
|
||||
- 需求创建后**只能是 draft 状态**,禁止自动提交
|
||||
- 从 draft 到提交评审需通过 **4 道门禁**(讨论 → 确认 → PRD → 完整性检查)
|
||||
- 提交评审使用 `/req submit`(原 `/req review`)
|
||||
|
||||
请使用 `/req` 命令,详细参考见 `req` 和 `req-commands` 技能。
|
||||
124
sync-skills.sh
124
sync-skills.sh
@@ -1,124 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Sync local skills to marketplace plugins
|
||||
# Usage: ./sync-skills.sh [marketplace-dir]
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
LOCAL_SKILLS_DIR="$HOME/.claude/skills"
|
||||
MARKETPLACE_DIR="${1:-$(dirname "$0")}"
|
||||
PLUGINS_DIR="$MARKETPLACE_DIR/skills"
|
||||
|
||||
echo "🔄 Syncing skills to marketplace..."
|
||||
echo "Source: $LOCAL_SKILLS_DIR"
|
||||
echo "Target: $PLUGINS_DIR"
|
||||
echo ""
|
||||
|
||||
# Check if local skills directory exists
|
||||
if [ ! -d "$LOCAL_SKILLS_DIR" ]; then
|
||||
echo "❌ Error: Local skills directory not found: $LOCAL_SKILLS_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Track changes
|
||||
new_count=0
|
||||
updated_count=0
|
||||
unchanged_count=0
|
||||
|
||||
# Loop through each local skill
|
||||
for skill_dir in "$LOCAL_SKILLS_DIR"/*; do
|
||||
# Skip non-directories and special files
|
||||
if [ ! -d "$skill_dir" ] || [ "$(basename "$skill_dir")" = ".git" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Skip registry.yaml if it exists as a directory
|
||||
if [ "$(basename "$skill_dir")" = "registry.yaml" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
skill_name=$(basename "$skill_dir")
|
||||
plugin_name="${skill_name}-plugin"
|
||||
plugin_dir="$PLUGINS_DIR/$plugin_name"
|
||||
|
||||
# Check if SKILL.md exists
|
||||
if [ ! -f "$skill_dir/SKILL.md" ]; then
|
||||
echo "⚠️ Skipping $skill_name (no SKILL.md)"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if plugin already exists
|
||||
if [ -d "$plugin_dir" ]; then
|
||||
# Compare SKILL.md files
|
||||
if diff -q "$skill_dir/SKILL.md" "$plugin_dir/skills/SKILL.md" > /dev/null 2>&1; then
|
||||
echo "✓ $skill_name (unchanged)"
|
||||
((unchanged_count++))
|
||||
else
|
||||
echo "📝 $skill_name (updated)"
|
||||
cp "$skill_dir/SKILL.md" "$plugin_dir/skills/"
|
||||
((updated_count++))
|
||||
fi
|
||||
else
|
||||
echo "➕ $skill_name (new)"
|
||||
|
||||
# Create plugin directory structure
|
||||
mkdir -p "$plugin_dir/.claude-plugin"
|
||||
mkdir -p "$plugin_dir/skills"
|
||||
|
||||
# Copy SKILL.md
|
||||
cp "$skill_dir/SKILL.md" "$plugin_dir/skills/"
|
||||
|
||||
# Extract description from SKILL.md frontmatter
|
||||
description=$(grep "^description:" "$skill_dir/SKILL.md" | sed 's/^description: *//' | tr -d '\n\r')
|
||||
if [ -z "$description" ]; then
|
||||
description="Plugin for $skill_name"
|
||||
fi
|
||||
|
||||
# Create plugin.json
|
||||
cat > "$plugin_dir/.claude-plugin/plugin.json" << EOF
|
||||
{
|
||||
"name": "$plugin_name",
|
||||
"description": "$description",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "qiudl"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
((new_count++))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "📊 Summary:"
|
||||
echo " New: $new_count"
|
||||
echo " Updated: $updated_count"
|
||||
echo " Unchanged: $unchanged_count"
|
||||
echo ""
|
||||
|
||||
# Regenerate marketplace.json if there are changes
|
||||
if [ $new_count -gt 0 ] || [ $updated_count -gt 0 ]; then
|
||||
echo "🔄 Regenerating marketplace.json..."
|
||||
cd "$MARKETPLACE_DIR"
|
||||
|
||||
# Run the generate script if it exists
|
||||
if [ -f "generate-marketplace.py" ]; then
|
||||
python3 generate-marketplace.py
|
||||
else
|
||||
echo "⚠️ Warning: generate-marketplace.py not found, skipping marketplace.json regeneration"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Sync complete! Changes ready to commit."
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " cd $MARKETPLACE_DIR"
|
||||
echo " git status"
|
||||
echo " git add ."
|
||||
echo " git commit -m 'Sync skills from local'"
|
||||
echo " git push"
|
||||
else
|
||||
echo "✅ All plugins are up to date!"
|
||||
fi
|
||||
Reference in New Issue
Block a user