skills/ → skills-dev(9), skills-req(10), skills-ops(4), skills-integration(8), skills-biz(4), skills-workflow(7) generate-marketplace.py 改为自动扫描所有 skills-* 目录。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
52 KiB
需求部署 Skill (req-deploy)
概述
本技能专门负责需求的部署发布工作,包括:
- Docker 镜像构建与推送
- 镜像大小检查与优化
- Staging 环境部署(SSH 手动部署)
- Production 环境部署(Jenkins API 自动触发)
- API 验证与健康检查
- 前端截图验证(本机、Staging、Production)
- 部署任务文档创建
- iOS 应用部署(通过 cn-dev 安装到 iPhone)
- Android 应用部署(通过 fuxing 电脑安装到 Android 设备)
部署流程概览
Web 应用部署流程
阶段1: 本机测试
↓
阶段2: Staging 部署
├── 构建镜像 (:test 标签)
├── 镜像大小检查
├── 推送 DockerHub
├── SSH 手动部署
├── API 验证
└── 前端截图验证
↓
阶段3: Production 部署
├── 重新标记 :test → :prod(无需重新构建)
├── 推送 :prod 标签到 DockerHub
├── Jenkins API 触发部署(Job: ai-proj-production,IMAGE_TAG=prod)
├── API 健康检查
├── 生产截图验证
└── 创建部署任务文档
iOS 应用部署流程
阶段1: 本机代码提交
├── git add -A
├── git commit
└── git push origin main
↓
阶段2: cn-dev 部署
├── SSH 到 cn-dev
├── git pull 更新代码
├── Xcode 构建
└── 安装到 iPhone
↓
阶段3: 功能验证
├── App 启动检查
├── 登录功能测试
└── 新功能验证
Android 应用部署流程
阶段1: 本机代码提交
├── git add -A
├── git commit
└── git push origin main
↓
阶段2: fuxing 电脑部署 (100.90.190.119)
├── SSH 到 fuxing
├── git pull 更新代码
├── Gradle 构建 APK
└── ADB 安装到 Android 设备
↓
阶段3: 功能验证
├── App 启动检查
├── 登录功能测试
└── 新功能验证
0. 部署前变更检测(必须)
⚠️ 每次部署前必须执行变更检测,防止漏部署服务。
0.1 Prod 镜像 Commit 对比
对比本地最新 commit 与 prod 镜像内嵌的 commit,判断哪些服务需要重新构建:
# 获取 prod 镜像内嵌的 commit(需要先 pull)
PROD_BE_COMMIT=$(docker inspect saltthing123/ai-proj-backend:prod --format '{{index .Config.Labels "git.commit"}}' 2>/dev/null || echo "unknown")
PROD_FE_COMMIT=$(docker inspect saltthing123/ai-proj-frontend:prod --format '{{index .Config.Labels "git.commit"}}' 2>/dev/null || echo "unknown")
LOCAL_COMMIT=$(git rev-parse HEAD)
echo "本地 HEAD: $LOCAL_COMMIT"
echo "Prod 后端: $PROD_BE_COMMIT"
echo "Prod 前端: $PROD_FE_COMMIT"
# 检查各服务是否有变更
if [ "$PROD_BE_COMMIT" != "unknown" ] && [ "$PROD_BE_COMMIT" != "$LOCAL_COMMIT" ]; then
BE_CHANGES=$(git diff "$PROD_BE_COMMIT"..HEAD --name-only -- backend/ | wc -l | tr -d ' ')
echo "后端变更: $BE_CHANGES 个文件"
else
BE_CHANGES="?"
echo "后端: 无法对比(镜像无 commit label),使用 git diff 兜底"
fi
if [ "$PROD_FE_COMMIT" != "unknown" ] && [ "$PROD_FE_COMMIT" != "$LOCAL_COMMIT" ]; then
FE_CHANGES=$(git diff "$PROD_FE_COMMIT"..HEAD --name-only -- frontend/ | wc -l | tr -d ' ')
echo "前端变更: $FE_CHANGES 个文件"
else
FE_CHANGES="?"
echo "前端: 无法对比(镜像无 commit label),使用 git diff 兜底"
fi
0.2 Git Diff 兜底(镜像无 label 时)
当镜像没有 git.commit label 时,用 git log 查找上次部署的 commit:
# 查看最近变更涉及的目录
git diff HEAD~N --name-only | cut -d/ -f1 | sort -u
0.3 决策树
变更检测结果?
├── backend/ 有变更 → 必须构建 backend 镜像
├── frontend/ 有变更 → 必须构建 frontend 镜像
├── 两者都有变更 → 构建全部
├── mcp-task-bridge/ → 本地 npm run build(不走 Docker)
└── 仅 deploy/ → 检查 docker-compose 配置变更
| 变更范围 | 构建什么 | 跳过什么 | 时间节省 |
|---|---|---|---|
| 仅 backend/ | ai-proj-backend:test |
frontend 构建 + 推送 | ~5 min |
| 仅 frontend/ | ai-proj-frontend:test |
backend 构建 + 推送 | ~3 min |
| 两者都有 | 全部构建 | 无 | 0 |
| 仅 mcp-task-bridge/ | 无 Docker 构建 | 全部跳过,本地 npm run build 即可 |
~8 min |
Jenkins 只拉取有新 digest 的镜像,未更新的镜像不会重新部署容器。因此只推送变更的服务镜像即可。
0.4 Dockerfile 嵌入 Commit Label
⚠️ 构建时必须传入 GIT_COMMIT,否则下次部署无法对比:
docker build \
--build-arg GIT_COMMIT=$(git rev-parse HEAD) \
--target production --platform linux/amd64 \
-t saltthing123/ai-proj-backend:test \
-f backend/Dockerfile backend/
Dockerfile 需添加(一次性):
ARG GIT_COMMIT=unknown
LABEL git.commit=$GIT_COMMIT
1. 镜像构建与推送
1.1 镜像大小阈值
| 服务类型 | 正常大小 | ⚠️ 警告阈值 | ❌ 错误阈值 | 说明 |
|---|---|---|---|---|
| Go 后端 | 50-100MB | > 200MB | > 500MB | 使用多阶段构建 + alpine |
| Node 前端(生产) | 100-300MB | > 500MB | > 1GB | Nginx + 静态文件 |
| Node 前端(测试) | 500MB-1GB | > 1.5GB | > 2GB | 包含测试工具 |
| iOS 应用 | 50-150MB | > 300MB | > 500MB | 二进制 + 资源文件 |
| Android 应用 | 30-80MB | > 150MB | > 300MB | APK 文件 |
1.2 Staging 镜像构建(:test 标签)
# 1. 进入项目根目录
cd /Users/donglinlai/coding/qiudl/new-ai-proj
# 2. 构建后端镜像(Go + Alpine,使用 production target,嵌入 commit)
docker build \
--build-arg GIT_COMMIT=$(git rev-parse HEAD) \
--target production \
--platform linux/amd64 \
-t saltthing123/ai-proj-backend:test \
-f backend/Dockerfile \
backend/
# 3. 构建前端镜像(React + Nginx,使用 production target,嵌入 commit)
docker build \
--build-arg GIT_COMMIT=$(git rev-parse HEAD) \
--target production \
--platform linux/amd64 \
-t saltthing123/ai-proj-frontend:test \
-f frontend/Dockerfile \
frontend/
# 4. 检查镜像大小
docker images saltthing123/ai-proj-backend:test --format "{{.Repository}}:{{.Tag}} {{.Size}}"
docker images saltthing123/ai-proj-frontend:test --format "{{.Repository}}:{{.Tag}} {{.Size}}"
⚠️ 关键注意事项:
- 必须使用
--target production,否则默认构建最后一个 stage(testing),导致镜像过大 - 前端 Dockerfile 的 production stage 使用 Nginx 提供静态文件服务
- 后端 Dockerfile 的 production stage 使用 Alpine Linux 基础镜像
1.3 镜像大小检查
# 获取镜像大小(字节)
BACKEND_SIZE=$(docker images saltthing123/ai-proj-backend:test --format "{{.Size}}")
FRONTEND_SIZE=$(docker images saltthing123/ai-proj-frontend:test --format "{{.Size}}")
echo "Backend: $BACKEND_SIZE"
echo "Frontend: $FRONTEND_SIZE"
自动检查逻辑:
IF 后端 > 200MB THEN
⚠️ 警告:后端镜像过大,执行排查流程
ELSE IF 后端 > 500MB THEN
❌ 错误:后端镜像异常,暂停部署
END IF
IF 前端 > 500MB THEN
⚠️ 警告:前端镜像过大,执行排查流程
ELSE IF 前端 > 1GB THEN
❌ 错误:前端镜像异常,暂停部署
END IF
1.4 镜像过大排查流程
# 1. 查看镜像层级(找出哪层占用空间大)
docker history saltthing123/ai-proj-frontend:test --human=false --no-trunc
# 2. 检查 Dockerfile 配置
cat frontend/Dockerfile | grep -E "^FROM|^RUN|^COPY"
# 3. 常见问题检查清单
问题1: ❌ 未指定 --target,构建了 testing stage
解决:添加 --target production
问题2: ❌ COPY 了 node_modules 或源代码到生产镜像
解决:确保 production stage 只 COPY 构建产物(/app/build)
问题3: ❌ 安装了 devDependencies
解决:确保只运行 npm ci --only=production(或使用 builder stage)
问题4: ❌ 包含了测试文件或工具
解决:使用 .dockerignore 排除测试文件
# 4. 进入镜像检查文件内容(调试用)
docker run --rm -it --entrypoint /bin/sh saltthing123/ai-proj-frontend:test
# 在容器内执行:
# ls -lh /app
# du -sh /app/*
# exit
# 5. 对比正确的 Dockerfile 示例
cat << 'EOF'
# ✅ 正确的前端 Dockerfile(production stage)
FROM nginx:alpine AS production
RUN apk --no-cache add curl && rm -rf /var/cache/apk/*
COPY --from=builder /app/build /usr/share/nginx/html # 只拷贝构建产物
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
EOF
1.5 推送到 DockerHub
# 推送镜像到 DockerHub
docker push saltthing123/ai-proj-backend:test
docker push saltthing123/ai-proj-frontend:test
# 验证推送成功(可选)
docker pull saltthing123/ai-proj-backend:test
docker pull saltthing123/ai-proj-frontend:test
1.6 镜像推送时显示大小(必须)
⚠️ 关键要求: 在推送镜像过程中或推送完成后,必须向用户显示镜像大小信息。
显示格式:
=== 镜像构建完成 ===
后端镜像: saltthing123/ai-proj-backend:test
大小: 96MB
状态: ✅ 正常 (< 200MB 阈值)
前端镜像: saltthing123/ai-proj-frontend:test
大小: 89.4MB
状态: ✅ 正常 (< 500MB 阈值)
正在推送镜像...
获取镜像大小的方法:
# 方法1: 本地 Docker 镜像(构建后)
docker images saltthing123/ai-proj-backend:test --format "{{.Size}}"
# 输出: 96MB
# 方法2: 使用 buildx 构建时,从构建日志中提取
# 构建日志最后会显示: "exporting manifest list sha256:xxx done"
# 然后可以通过 docker manifest inspect 获取
# 方法3: 推送后从 DockerHub API 获取
curl -s "https://hub.docker.com/v2/repositories/saltthing123/ai-proj-backend/tags/test" | jq '.full_size'
异常处理:
- 如果镜像大小超过警告阈值,显示 ⚠️ 并提示排查
- 如果镜像大小超过错误阈值,显示 ❌ 并暂停部署,要求用户确认
- 如果无法获取镜像大小,显示 "⚠️ 无法获取镜像大小" 并继续
2. Staging 环境部署
2.0 ⚠️ Staging 部署前检查清单(必须)
重要: 在构建和部署 Staging 环境之前,必须完成以下检查清单,确保不遗漏关键功能。
2.0.1 Git 提交日志检查
在部署前,检查最近的 git 提交,识别关键功能变更:
# 1. 查看最近提交(识别关键功能)
git log --oneline -20
# 2. 重点关注以下关键词的提交:
# - feat: 新功能(特别是导航菜单、新页面)
# - migration: 数据库迁移
# - route: 路由变更
# - menu/nav: 导航菜单变更
2.0.2 导航菜单入口检查
如果提交中包含导航菜单变更,必须:
-
检查 Layout.tsx 中的菜单配置:
# 查看导航菜单相关变更 git diff HEAD~10 -- frontend/src/components/Layout.tsx | grep -A5 -B5 "menuItems\|SubMenu\|Menu.Item" -
确认新菜单路由已配置:
# 检查路由文件 git diff HEAD~10 -- frontend/src/routes/*.tsx -
验证构建产物包含新代码:
# 构建后检查(在部署前验证) docker run --rm saltthing123/ai-proj-frontend:test sh -c \ "grep -r '<关键路由关键词>' /usr/share/nginx/html/static/js/ | wc -l"
2.0.3 数据库迁移检查
如果提交中包含数据库迁移,必须在部署前应用迁移:
# 1. 检查新增迁移文件
git diff HEAD~10 --name-only | grep -E "migrations/.*\.sql$"
# 2. 列出待执行的迁移
ls -la backend/migrations/*.sql | tail -10
# 3. 在 Staging 数据库执行迁移(以 Singapore 服务器为例)
ssh singapore "docker exec ai_postgres_staging psql -U ai_staging_user ai_project_staging -f /path/to/migration.sql"
# 4. 验证迁移成功
ssh singapore "docker exec ai_postgres_staging psql -U ai_staging_user ai_project_staging -c '\dt'"
⚠️ 迁移执行顺序:
- 数据库迁移必须在后端部署之前完成
- 先执行
_up.sql,回滚时执行_down.sql
2.0.4 前端环境变量检查(CRA 特殊处理)
重要: CRA (Create React App) 在构建时只读取
.env.production文件,忽略 Docker ENV/ARG 传入的环境变量。
Staging 构建的正确流程:
# 1. 备份原 .env.production
cp frontend/.env.production frontend/.env.production.bak
# 2. 用 .env.staging 替换 .env.production
cp frontend/.env.staging frontend/.env.production
# 3. 构建镜像(必须使用 --no-cache 确保最新代码)
docker build --no-cache --target production --platform linux/amd64 \
-t saltthing123/ai-proj-frontend:test \
-f frontend/Dockerfile \
frontend/
# 4. 恢复原 .env.production
mv frontend/.env.production.bak frontend/.env.production
# 5. 推送镜像
docker push saltthing123/ai-proj-frontend:test
验证环境变量正确注入:
# 检查构建产物中的环境变量
docker run --rm saltthing123/ai-proj-frontend:test sh -c \
"grep -o 'REACT_APP_ENVIRONMENT=[^,]*' /usr/share/nginx/html/static/js/*.js | head -1"
# 期望输出: REACT_APP_ENVIRONMENT=staging
2.0.5 Docker 缓存清理
关键: 当有重要代码变更时,必须使用
--no-cache避免使用缓存的旧代码层。
# 需要 --no-cache 的场景:
# - 导航菜单变更
# - 路由配置变更
# - 环境变量变更
# - 依赖包更新
docker build --no-cache --target production --platform linux/amd64 \
-t saltthing123/ai-proj-frontend:test \
-f frontend/Dockerfile \
frontend/
2.0.6 检查清单汇总表
| 检查项 | 命令/操作 | 必须 |
|---|---|---|
| Git 提交日志 | git log --oneline -20 |
✅ |
| 识别导航菜单变更 | 检查 Layout.tsx 差异 | 如有变更 |
| 识别数据库迁移 | 检查 migrations/ 目录 | 如有变更 |
| 执行数据库迁移 | SSH 到 staging 执行 SQL | 如有变更 |
| 替换 .env.production | 用 .env.staging 替换 | ✅ |
| 使用 --no-cache 构建 | docker build --no-cache |
推荐 |
| 验证构建产物 | 检查关键代码存在 | ✅ |
| 恢复 .env.production | 还原原文件 | ✅ |
2.1 部署前准备
环境信息(从项目配置读取):
- Staging 服务器:
43.134.28.147(Singapore,新加坡腾讯云) - 项目路径:
/opt/ai-project-staging - Docker Compose 文件:
docker-compose.yml+docker-compose.override.yml - Docker Compose: 使用
docker compose(v2),v1 已卸载
2.2 部署方案选择
方案 A:Override 配置(推荐)
使用 docker-compose override 文件覆盖镜像配置:
# 1. SSH 到 staging 服务器 (Singapore)
ssh singapore
# 或: ssh ubuntu@43.134.28.147
# 2. 进入项目目录
cd /opt/ai-project-staging
# 3. 创建 override 文件(使用 DockerHub 镜像代替本地构建)
cat > docker-compose.staging-test.yml <<'EOF'
version: '3.8'
services:
backend-staging:
image: saltthing123/ai-proj-backend:test
build: null # 覆盖 build 配置,不再本地构建
frontend-staging:
image: saltthing123/ai-proj-frontend:test
build: null # 覆盖 build 配置,不再本地构建
EOF
# 4. 拉取最新镜像
docker pull saltthing123/ai-proj-backend:test
docker pull saltthing123/ai-proj-frontend:test
# 5. 停止旧服务
docker compose -f deploy/docker-compose.staging.yml \
-f docker-compose.staging-test.yml \
down
# 6. 启动新服务
docker compose -f deploy/docker-compose.staging.yml \
-f docker-compose.staging-test.yml \
up -d backend-staging frontend-staging
# 7. 查看服务状态
docker compose -f deploy/docker-compose.staging.yml \
-f docker-compose.staging-test.yml \
ps
# 8. 查看启动日志(确认无错误)
docker logs -f ai_backend_staging --tail 50
方案 B:标签重映射(更简单)
直接拉取镜像并重新标记为 staging 标签:
# 1. SSH 到 staging 服务器 (Singapore)
ssh singapore
# 或: ssh ubuntu@43.134.28.147
# 2. 拉取最新镜像
docker pull saltthing123/ai-proj-backend:test
docker pull saltthing123/ai-proj-frontend:test
# 3. 重新标记为 staging 标签(如果现有配置使用 staging 标签)
docker tag saltthing123/ai-proj-backend:test saltthing123/ai-proj-backend:staging
docker tag saltthing123/ai-proj-frontend:test saltthing123/ai-proj-frontend:staging
# 4. 重启服务
cd /opt/ai-project-staging
docker compose -f deploy/docker-compose.staging.yml up -d --force-recreate backend-staging frontend-staging
# 5. 查看服务状态
docker compose -f deploy/docker-compose.staging.yml ps
# 6. 查看日志
docker logs -f ai_backend_staging --tail 50
2.3 部署验证清单
部署完成后,必须检查以下项目:
# 1. 容器状态检查
docker ps | grep "ai_backend_staging\|ai_frontend_staging"
# 期望:Status 为 "Up",Health 为 "healthy"
# 2. 后端日志检查(无严重错误)
docker logs ai_backend_staging --tail 100 | grep -iE "error|panic|fatal"
# 期望:无 FATAL 或 PANIC 错误(INFO 级别错误可忽略)
# 3. 前端日志检查(Nginx 正常启动)
docker logs ai_frontend_staging --tail 50
# 期望:看到 "nginx: configuration file ... test is successful"
# 4. 端口监听检查
netstat -tlnp | grep -E "8080|3000"
# 期望:8080(后端)和 3000(前端)端口被 Docker 监听
# 5. 重启 MCP bridge(后端部署后必须执行)
docker compose restart mcp-task-bridge-staging 2>/dev/null || echo "⚠️ mcp-task-bridge-staging 不存在,跳过"
sleep 5
docker logs mcp-task-bridge-staging --tail 5 2>/dev/null
# 期望:bridge 正常启动,无连接错误
⚠️ MCP bridge 重启说明:
- 后端新增 API 端点后,mcp-task-bridge 需要重启才能发现新端点
- 如果 staging 未部署 mcp-task-bridge,此步骤自动跳过
- 重启后等待 5 秒确保 bridge 完成初始化
3. API 验证
3.1 Staging API 验证
部署完成后,执行 API 健康检查:
# 1. 健康检查接口(内部访问)
curl -f http://localhost:8080/health
# 期望:200 OK,返回 {"status":"ok"}
# 2. 健康检查接口(外部访问,如有 Nginx 反向代理)
curl -f https://staging.pipexerp.com/api/v1/health
# 期望:200 OK
# 3. 测试需求相关 API(项目手册列表)
curl -X GET "http://localhost:8080/api/v1/manuals?page=1&pageSize=20" \
-H "Content-Type: application/json"
# 期望:返回 401(需要认证)或 200(返回数据)
# 4. 如需认证,从凭据文件获取 token
source ~/.config/devops/credentials.env
TOKEN=$(curl -s -X POST "$AI_PROJ_API_URL/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"$AI_PROJ_USER\",\"password\":\"$AI_PROJ_PASS\"}" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['access_token'])")
curl -X GET "http://localhost:8080/api/v1/manuals?page=1&pageSize=20" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN"
# 期望:200 OK,返回手册列表数据
验证结果记录:
## Staging API 验证
| 接口 | 方法 | 状态码 | 响应 | 结果 |
|------|------|--------|------|------|
| /health | GET | 200 | {"status":"ok"} | ✅ |
| /api/v1/manuals | GET | 401 | 需要认证 | ✅ |
| /api/v1/manuals (with token) | GET | 200 | 返回数据 | ✅ |
3.2 Production API 验证
Production 部署后,执行相同的验证流程:
# 1. 健康检查接口
curl -f https://ai.pipexerp.com/api/v1/health
# 期望:200 OK
# 2. 测试需求相关 API(token 从凭据文件获取)
source ~/.config/devops/credentials.env
PROD_TOKEN=$(curl -s -X POST "$AI_PROJ_API_URL/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"$AI_PROJ_USER\",\"password\":\"$AI_PROJ_PASS\"}" | python3 -c "import sys,json; print(json.load(sys.stdin)['data']['access_token'])")
curl -X GET "https://ai.pipexerp.com/api/v1/manuals?page=1&pageSize=20" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $PROD_TOKEN"
# 期望:200 OK,返回生产数据
3.3 变更定向验证(部署后必做)
健康检查只能证明服务活着,不能证明修复生效。 部署后必须针对本次变更做定向验证。
执行方式:根据 commit 内容设计验证用例,通过 API 或 MCP CLI 调用验证。
# 示例:验证 delivery_stage 字段修复
# 1. 找一个有 delivery_stage 的需求
echo '{"jsonrpc":"2.0","id":1,...}' | \
TASK_API_BASE="https://ai.pipexerp.com/api/v1" ... \
node dist/index.js 2>/dev/null | python3 -c "..."
# 2. 确认 delivery_stage 字段有值(修复前为 null)
# 示例:验证新增 API 端点
curl -sf "https://ai.pipexerp.com/api/v1/NEW_ENDPOINT" -H "Authorization: ..." | head -1
# 确认返回 200 而非 404
验证结果记录格式:
### 变更定向验证
| 变更 | 验证方式 | 期望 | 实际 | 结果 |
|------|---------|------|------|------|
| delivery_stage API 修复 | GET /requirements/897 检查字段 | delivery_stage 有值 | backlog | ✅ |
| sync 工具新增 | MCP dry run | 返回 success | success | ✅ |
4. 前端截图验证
4.1 本机截图验证(阶段1)
本机测试阶段,使用 chrome-dev MCP 工具截图验证:
// 1. 打开本机前端页面
mcp__chrome-dev__navigate_page({
url: "http://localhost:3000/project-manuals"
})
// 2. 等待页面加载完成
mcp__chrome-dev__wait_for({
selector: "table", // 等待表格加载
timeout: 10000
})
// 3. 截图验证
mcp__chrome-dev__take_screenshot({
name: "local-project-manuals-page"
})
验证要点:
- 页面正常渲染,无白屏或错误
- 表格显示手册列表数据
- 搜索框、筛选器正常显示
- 操作按钮(查看、编辑)正常显示
4.2 Staging 截图验证(阶段2)
Staging 部署后,截图验证:
// 1. 打开 Staging 环境页面
mcp__chrome-dev__navigate_page({
url: "https://staging.pipexerp.com/project-manuals"
})
// 2. 等待页面加载
mcp__chrome-dev__wait_for({
selector: "table",
timeout: 10000
})
// 3. 截图验证
mcp__chrome-dev__take_screenshot({
name: "staging-project-manuals-page"
})
验证要点:
- 页面正常渲染
- API 数据加载成功
- 功能点正确显示(与本机测试一致)
4.3 Production 截图验证(阶段3)
Production 部署后,必须进行截图验证:
// 1. 等待 Jenkins 部署完成(约 30 秒)
// 2. 打开生产环境页面
mcp__chrome-dev__navigate_page({
url: "https://ai.pipexerp.com/project-manuals"
})
// 3. 等待页面加载
mcp__chrome-dev__wait_for({
selector: "table",
timeout: 10000
})
// 4. 截图验证
mcp__chrome-dev__take_screenshot({
name: "production-project-manuals-page"
})
验证要点:
- 页面正常渲染
- 生产数据正确显示
- 核心功能点正确渲染
- 无 JavaScript 错误
⚠️ 如截图显示异常,立即回滚并排查问题。
5. Production 部署(Jenkins)
5.0 镜像标签策略
| 标签 | 用途 | 说明 |
|---|---|---|
:test |
Staging | 本地构建后推送 |
:prod |
Production 语义标签 | 由 :test 重新标记,无需重建 |
:latest |
Production 实际拉取 | docker-compose 默认使用此标签 |
⚠️ 必须同时推送 :prod 和 :latest。生产 docker-compose 使用 ${IMAGE_TAG:-latest},缺省拉取 :latest。只推 :prod 不推 :latest 会导致部署不生效。
Staging → Production 标签转换(避免重新构建):
# 将已验证的 staging 镜像标记为 prod + latest 并推送
for svc in backend frontend; do
docker tag saltthing123/ai-proj-$svc:test saltthing123/ai-proj-$svc:prod
docker tag saltthing123/ai-proj-$svc:test saltthing123/ai-proj-$svc:latest
docker push saltthing123/ai-proj-$svc:prod
docker push saltthing123/ai-proj-$svc:latest
done
5.1 Jenkins 部署配置
Jenkins 服务器信息:
- URL:
https://jenkins.pipexerp.com(凭据在~/.config/devops/credentials.env) - Job:
ai-proj-production(生产部署专用) - 参数:
IMAGE_TAG(默认latest)、SKIP_HEALTH_CHECK(默认 false) - 认证:HTTP Basic Auth(
$JENKINS_USER:$JENKINS_TOKEN)
生产服务器部署路径:/opt/ai-project/docker-compose.dockerhub.yml
- 镜像标签通过
${IMAGE_TAG:-prod}动态注入
5.2 触发 Jenkins 构建
使用 Jenkins API 触发部署:
source ~/.config/devops/credentials.env
# 触发构建(IMAGE_TAG 默认已是 prod,可省略参数)
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
"$JENKINS_URL/job/ai-proj-production/buildWithParameters?IMAGE_TAG=prod&SKIP_HEALTH_CHECK=false")
echo "HTTP: $HTTP_CODE" # 期望 201
# 获取最新构建编号
sleep 5
BUILD_NUMBER=$(curl -s -u "$JENKINS_USER:$JENKINS_TOKEN" \
"$JENKINS_URL/job/ai-proj-production/api/json" | \
python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('lastBuild',{}).get('number',''))")
echo "Build #$BUILD_NUMBER"
# 轮询构建状态
for i in $(seq 1 30); do
sleep 10
RESULT=$(curl -s -u "$JENKINS_USER:$JENKINS_TOKEN" \
"$JENKINS_URL/job/ai-proj-production/$BUILD_NUMBER/api/json" | \
python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('result','null'), d.get('building', False))")
echo "[$i] $RESULT"
if echo "$RESULT" | grep -qE "^(SUCCESS|FAILURE|ABORTED)"; then break; fi
done
⚠️ Jenkins CSRF 注意事项:
- 修改 Job 配置时,
config.xmlPOST 接口容易报 500 - 推荐方案:改用 Script Console(
/scriptText)
# 通过 Script Console 修改 Job 参数默认值
CRUMB=$(curl -s -c /tmp/jc.txt -u "$JENKINS_USER:$JENKINS_TOKEN" \
"$JENKINS_URL/crumbIssuer/api/json" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['crumb'])")
curl -s -X POST \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
-b /tmp/jc.txt \
-H "Jenkins-Crumb: $CRUMB" \
--data-urlencode 'script=
def job = Jenkins.instance.getItem("ai-proj-production")
def params = job.getProperty(hudson.model.ParametersDefinitionProperty.class)
params.getParameterDefinitions().each { p ->
if (p.name == "IMAGE_TAG") { p.defaultValue = "prod" }
}
job.save()
println "Done"
' "$JENKINS_URL/scriptText"
5.3 Jenkins 构建失败处理
如果构建失败,执行以下排查步骤:
# 1. 获取构建日志
curl -s -u "$JENKINS_USER:$JENKINS_TOKEN" \
"$JENKINS_URL/job/$JENKINS_JOB/$BUILD_NUMBER/consoleText" > jenkins-build.log
# 2. 查看错误信息
cat jenkins-build.log | grep -iE "error|failed|exception"
# 3. 常见问题排查
问题1: 镜像拉取失败
- 检查 DockerHub 推送是否成功
- 检查生产服务器网络是否正常
问题2: 容器启动失败
- 查看容器日志
- 检查环境变量配置
问题3: 健康检查失败
- 检查服务端口是否正常
- 检查数据库连接
# 4. 提供解决方案并通知用户
5.4 部署结果写入需求历史
⚠️ 关键步骤:Jenkins 部署完成后(无论成功或失败),必须将部署摘要写入需求的操作历史。
前置条件:部署必须关联到某个需求(有 REQ-ID)。
写入方式:通过 ai-proj MCP 的需求历史 API:
# 部署成功时
curl -X POST "https://ai.pipexerp.com/api/v1/requirements/${REQ_ID}/history" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"action": "deployed",
"field_name": "environment",
"new_value": "production",
"comment": "Jenkins Build #${BUILD_NUMBER} SUCCESS\n耗时: ${DURATION}\n镜像: ${IMAGE_NAME}:${IMAGE_TAG} (${IMAGE_SIZE})\nCommit: ${COMMIT_HASH}"
}'
# 部署失败时
curl -X POST "https://ai.pipexerp.com/api/v1/requirements/${REQ_ID}/history" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"action": "deployed",
"field_name": "environment",
"new_value": "production",
"comment": "Jenkins Build #${BUILD_NUMBER} FAILURE\n错误: ${ERROR_SUMMARY}"
}'
在 req-deploy 技能流程中的位置:
Jenkins 构建完成
↓
获取构建结果(BUILD_NUMBER, RESULT, DURATION)
↓
API 健康检查
↓
★ 调用 POST /requirements/{id}/history 记录部署结果
↓
前端截图验证
↓
创建部署文档
comment 字段模板:
Jenkins Build #{BUILD_NUMBER} {RESULT}
环境: {staging|production}
耗时: {DURATION}
镜像: {IMAGE_NAME}:{TAG} ({SIZE})
Commit: {HASH}
健康检查: {PASS|FAIL}
Staging 部署也需记录(new_value 设为 "staging")。
6. 部署任务文档创建
6.1 批量部署文档模板
部署完成后,必须创建部署文档并附加到部署批次任务:
# 批量部署文档 - {project} {date}
## 部署概览
| 项目 | 日期 | 包含需求数 | 环境 | 状态 |
|------|------|-----------|------|------|
| ai-proj | 2026-02-18 | 3 | staging → production | ✅ 完成 |
### 包含需求
| REQ ID | 标题 | delivery_stage 变更 |
|--------|------|-------------------|
| REQ-20260218-0013 | 用户认证功能 | testing → released |
| REQ-20260218-0015 | 手册管理功能 | testing → released |
| REQ-20260218-0016 | 阶段化管理优化 | testing → released |
---
## 镜像信息
| 服务 | 镜像 | 大小 | 阈值 | 状态 |
|------|------|------|------|------|
| 后端 | saltthing123/ai-proj-backend:test/:prod | 96MB | < 200MB | ✅ |
| 前端 | saltthing123/ai-proj-frontend:test/:prod | 89MB | < 500MB | ✅ |
---
## Staging 部署
- **部署方式**: SSH 手动部署
- **服务器**: singapore (43.134.28.147)
- **时间**: {timestamp}
### API 验证
| 接口 | 状态码 | 结果 |
|------|--------|------|
| /health | 200 | ✅ |
---
## Production 部署
- **部署方式**: Jenkins API
- **构建号**: #{BUILD_NUMBER}
- **状态**: {SUCCESS/FAILURE}
- **时间**: {timestamp}
### API 验证
| 接口 | 状态码 | 结果 |
|------|--------|------|
| /health | 200 | ✅ |
---
## 问题记录
(如无问题可省略)
## 总结
✅ {N} 个需求批量部署完成
✅ 所有需求已推进到 released
6.2 创建批量部署文档
// 1. 创建部署批次任务(由 /req deploy 流程创建)
const deployTask = create_task({
title: "【部署】ai-proj 2026-02-18 (3 requirements)"
})
// 2. 关联到所有选中需求
for (const req of selectedRequirements) {
link_tasks_to_requirement({
requirementId: req.id,
taskIds: [deployTask.id],
linkRole: "deploy"
})
}
// 3. 执行部署流程...
// 4. 部署成功后,附加文档
create-and-attach({
taskId: deployTask.id,
title: "批量部署文档 - ai-proj 2026-02-18",
content: batchDeployDocContent
})
// 5. 批量推进所有需求到 released
for (const req of selectedRequirements) {
advance_delivery_stage(req.id, "released")
}
// 6. 完成部署任务
complete_task(deployTask.id)
7. 与 req skill 集成
7.1 两层分离模型
需求维度:各需求独立走到 testing 完成 → 进入「待部署池」
部署维度:/req deploy → 收集所有待部署需求 → 一次构建部署 → 批量推进到 released
7.2 调用方式
在 req skill 中,/req deploy 命令调用本 skill:
### `/req deploy [--project <name>] [--env <environment>]`
这是**项目级批量部署**命令,不是单需求操作。
执行步骤:
1. 收集待部署需求(delivery_stage=testing, test 任务完成, 有 implementation 任务)
2. 展示待部署列表 → AskUserQuestion 确认范围
3. 创建部署批次任务,关联所有选中需求
4. **调用 req-deploy skill** 执行部署:
- 构建 Docker 镜像 + 镜像大小检查
- 推送到 DockerHub
- Staging: SSH 手动部署 + API 验证 + 截图验证
- Production: Jenkins API 触发 + API 验证 + 截图验证
5. 部署成功后批量推进需求到 released
6. 创建批量部署文档
7.3 标准工作流(两层分离)
需求维度(各需求独立):
/req test REQ-A → testing 完成 → 进入待部署池
/req test REQ-B → testing 完成 → 进入待部署池
/req test REQ-C → testing 完成 → 进入待部署池
部署维度(项目级批量):
/req deploy --env staging
↓
收集 REQ-A, REQ-B, REQ-C(待部署池)
↓
(req-deploy skill 执行 Staging 部署)
↓
Staging 验证通过
↓
/req deploy --env production
↓
(req-deploy skill 执行 Production 部署)
↓
批量推进 REQ-A/B/C → released
↓
/req done REQ-A, /req done REQ-B, /req done REQ-C
8. 环境配置管理
8.1 项目环境配置(从 .claude/settings.local.json 读取)
{
"REQUIREMENT_PROJECT": "ai-proj",
"STAGING_SERVER": "43.134.28.147",
"STAGING_SERVER_ALIAS": "singapore",
"STAGING_USER": "ubuntu",
"STAGING_PATH": "/opt/ai-project-staging",
"STAGING_NETWORK": "ai-project-staging_ai_staging_network",
"PRODUCTION_DOMAIN": "ai.pipexerp.com",
"DOCKERHUB_REPO": "saltthing123",
"JENKINS_URL": "http://116.62.148.151:8888",
"JENKINS_JOB": "ai-proj-deploy"
}
8.2 凭据文件(~/.config/devops/credentials.env)
统一存储所有部署相关凭据:
# AI-Proj API 配置
AI_PROJ_API_URL=https://ai.pipexerp.com
AI_PROJ_USER=<username>
AI_PROJ_PASS=<password>
# Jenkins 配置
JENKINS_URL=https://jenkins.pipexerp.com
JENKINS_USER=<username>
JENKINS_TOKEN=<token>
# 飞书部署通知
FEISHU_DEPLOY_WEBHOOK=<webhook_url>
⚠️ 安全提醒:凭据文件权限必须为 600(chmod 600 ~/.config/devops/credentials.env),防止其他用户读取。
REST API 标准用法(替代硬编码 token):
source ~/.config/devops/credentials.env
TOKEN=$(curl -s -X POST "$AI_PROJ_API_URL/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"$AI_PROJ_USER\",\"password\":\"$AI_PROJ_PASS\"}" \
| python3 -c "import sys,json; print(json.load(sys.stdin)['data']['access_token'])")
# 后续使用 -H "Authorization: Bearer $TOKEN"
8.3 服务配置
| 服务 | Staging | Production |
|---|---|---|
| 后端 | localhost:8080 | https://ai.pipexerp.com/api/v1 |
| 前端 | localhost:3000 | https://ai.pipexerp.com |
| 数据库 | postgres-staging:5432 | postgres-prod:5432 |
| Redis | redis-staging:6379 | redis-prod:6379 |
9. 安全约束
⚠️ 关键安全规则:
-
禁止自动 SSH 部署到生产服务器
- Staging 部署命令只显示,由用户手动执行
- Production 必须通过 Jenkins API 触发
-
构建失败必须显示错误原因
- 不能隐藏错误信息
- 必须提供解决方案
-
生产部署后必须进行截图验证
- 不能跳过此步骤
- 截图保存到部署任务文档中
-
部署完成后必须创建部署任务文档
- 记录部署步骤、问题、验证结果
- 关联到需求
10. 常见问题排查
Q1: 镜像构建失败
# 1. 查看构建日志
docker build ... 2>&1 | tee build.log
# 2. 检查 Dockerfile 语法
docker build --no-cache ...
# 3. 检查网络问题(npm install 超时)
docker build --network=host ...
Q2: 容器启动失败
# 1. 查看容器日志
docker logs <container-name> --tail 100
# 2. 检查环境变量
docker inspect <container-name> | jq '.[0].Config.Env'
# 3. 检查端口冲突
netstat -tlnp | grep <port>
Q3: API 返回 502/503
# 1. 检查后端容器状态
docker ps | grep backend
# 2. 检查后端日志
docker logs ai_backend_staging --tail 100
# 3. 检查数据库连接
docker exec ai_backend_staging curl http://localhost:8080/health
Q4: Jenkins 构建失败
# 1. 获取构建日志
curl -s -u "$USER:$TOKEN" "$JENKINS_URL/job/$JOB/$BUILD_NUMBER/consoleText"
# 2. 检查 Jenkins 服务状态
curl -s "$JENKINS_URL/login"
# 3. 检查生产服务器磁盘空间
ssh root@<prod-server> "df -h"
11. iOS 应用部署
11.1 部署概述
iOS 应用部署与 Web 应用不同,不使用 Docker 和 Jenkins,而是通过连接到 cn-dev (中国开发电脑) 进行真机安装。
部署流程:
本机代码提交
↓
SSH 到 cn-dev
↓
git pull 更新代码
↓
Xcode 构建
↓
安装到 iPhone
11.2 服务器信息
| 配置项 | 值 |
|---|---|
| 服务器别名 | cn-dev / coolbuy-dev |
| IP 地址 | 100.112.161.79 (Tailscale VPN) |
| 用户名 | coolbuy-dev |
| SSH 密钥 | ~/.ssh/id_ed25519_coolbuy_dev |
| 项目路径 | ~/coding/qiudl/new-ai-proj/AI-Proj-iOS |
11.3 SSH 配置
确保 ~/.ssh/config 包含以下配置:
Host cn-dev coolbuy-dev
HostName 100.112.161.79
User coolbuy-dev
IdentityFile ~/.ssh/id_ed25519_coolbuy_dev
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 6
11.4 部署步骤
步骤 1: 确保本机代码已提交
# 检查是否有未提交的更改
cd /Users/donglinlai/coding/qiudl/new-ai-proj/AI-Proj-iOS
git status
# 如有更改,提交并推送
git add -A
git commit -m "feat(iOS): 功能描述"
git push origin main
步骤 2: SSH 到 cn-dev 并更新代码
# SSH 连接到 cn-dev
ssh cn-dev
# 进入 iOS 项目目录
cd ~/coding/qiudl/new-ai-proj/AI-Proj-iOS
# 拉取最新代码
git pull origin main
# 确认代码已更新
git log -1 --oneline
步骤 3: 在 cn-dev 上构建并安装
# 在 cn-dev 上打开 Xcode 项目
open AI-Proj-iOS.xcodeproj
# 或者使用命令行构建(需要连接 iPhone)
xcodebuild -project AI-Proj-iOS.xcodeproj \
-scheme AI-Proj-iOS \
-destination 'platform=iOS,id=<设备UDID>' \
-configuration Debug \
build
通过 Xcode GUI 安装:
- 打开 Xcode 项目
- 选择目标设备(已连接的 iPhone)
- 点击 Run (⌘R) 构建并安装
11.5 一键部署命令
从 au-dev 一键执行部署流程:
# 1. 推送本机代码
cd /Users/donglinlai/coding/qiudl/new-ai-proj/AI-Proj-iOS
git add -A && git commit -m "feat(iOS): 更新" && git push origin main
# 2. SSH 到 cn-dev 更新代码
ssh cn-dev "cd ~/coding/qiudl/new-ai-proj/AI-Proj-iOS && git pull origin main && echo '✅ 代码已更新'"
# 3. 提示在 cn-dev 上打开 Xcode 安装
echo "请在 cn-dev 上执行: open ~/coding/qiudl/new-ai-proj/AI-Proj-iOS/AI-Proj-iOS.xcodeproj"
11.6 远程打开 Xcode(可选)
如果 cn-dev 上有 VNC 或远程桌面访问:
# 通过 SSH 在 cn-dev 上打开 Xcode(需要 GUI 环境)
ssh cn-dev "open ~/coding/qiudl/new-ai-proj/AI-Proj-iOS/AI-Proj-iOS.xcodeproj"
11.7 验证安装
安装完成后验证:
- App 启动检查:确保 App 能正常启动
- 登录功能:测试登录是否正常
- 新功能验证:测试本次部署的新功能
- API 连接:确保 App 能正确连接到后端 API
11.8 常见问题
Q1: SSH 连接超时
# 检查 Tailscale 状态
tailscale status
# 如果 cn-dev 离线,需要在 cn-dev 本地启动 Tailscale
Q2: Xcode 构建失败
# 清理构建缓存
cd ~/coding/qiudl/new-ai-proj/AI-Proj-iOS
rm -rf ~/Library/Developer/Xcode/DerivedData/AI-Proj-iOS-*
# 重新构建
xcodebuild clean -project AI-Proj-iOS.xcodeproj -scheme AI-Proj-iOS
Q3: iPhone 未识别
# 检查设备连接
xcrun xctrace list devices
# 信任开发者证书(在 iPhone 上)
# 设置 → 通用 → VPN与设备管理 → 信任开发者
11.9 iOS TestFlight 发布
11.9.1 概述
TestFlight 是 Apple 官方的内测分发平台,用于在正式发布到 App Store 之前进行内测。
TestFlight vs 直接安装对比:
| 特性 | 直接安装 (cn-dev) | TestFlight |
|---|---|---|
| 安装方式 | USB 连接 + Xcode | OTA 无线安装 |
| 设备数量 | 单台设备 | 最多 10,000 测试用户 |
| 需要 UDID | 是 | 否 |
| 审核 | 无 | Apple 自动审核 (约 1-2 天) |
| 有效期 | 无限制 | 90 天 |
| 适用场景 | 开发调试 | 内测分发、用户验收 |
11.9.2 前置条件
- Apple Developer 账号:需要有效的 Apple Developer Program 会员资格
- App Store Connect 配置:
- App 已在 App Store Connect 创建
- Bundle ID 已注册
- 签名证书和 Provisioning Profile 已配置
- Xcode 配置:
- 已登录 Apple Developer 账号
- 自动签名或手动签名已配置
11.9.3 构建 Archive
在 cn-dev 上构建发布版本:
# SSH 到 cn-dev
ssh cn-dev
# 进入项目目录
cd ~/coding/qiudl/new-ai-proj/AI-Proj-iOS
# 拉取最新代码
git pull origin main
# 方法 1: 通过 Xcode GUI
open AI-Proj-iOS.xcodeproj
# 菜单: Product → Archive
# 方法 2: 通过命令行
xcodebuild -project AI-Proj-iOS.xcodeproj \
-scheme AI-Proj-iOS \
-configuration Release \
-archivePath ~/Desktop/AI-Proj-iOS.xcarchive \
archive
# Archive 输出路径
# ~/Library/Developer/Xcode/Archives/YYYY-MM-DD/AI-Proj-iOS.xcarchive
11.9.4 上传到 App Store Connect
方法 1: 通过 Xcode Organizer (推荐)
1. 打开 Xcode → Window → Organizer
2. 选择刚构建的 Archive
3. 点击 "Distribute App"
4. 选择 "App Store Connect" → "Upload"
5. 选择分发选项:
- Include bitcode: 否 (可选)
- Upload your app's symbols: 是
- Manage Version and Build Number: 是
6. 选择签名证书和 Profile
7. 点击 "Upload"
8. 等待上传完成 (约 5-10 分钟)
方法 2: 通过 altool 命令行
# 导出 IPA
xcodebuild -exportArchive \
-archivePath ~/Desktop/AI-Proj-iOS.xcarchive \
-exportPath ~/Desktop/AI-Proj-iOS-Export \
-exportOptionsPlist ExportOptions.plist
# ExportOptions.plist 内容
cat > ExportOptions.plist << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>destination</key>
<string>upload</string>
<key>signingStyle</key>
<string>automatic</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
</dict>
</plist>
EOF
# 使用 altool 上传 (已废弃,建议使用 xcrun)
xcrun altool --upload-app \
-f ~/Desktop/AI-Proj-iOS-Export/AI-Proj-iOS.ipa \
-t ios \
-u "your-apple-id@example.com" \
-p "@keychain:AC_PASSWORD"
# 或使用 xcrun notarytool (Xcode 13+)
xcrun notarytool submit \
~/Desktop/AI-Proj-iOS-Export/AI-Proj-iOS.ipa \
--apple-id "your-apple-id@example.com" \
--password "@keychain:AC_PASSWORD" \
--team-id "YOUR_TEAM_ID"
11.9.5 TestFlight 内测分发
步骤 1: 等待处理
上传完成后,App Store Connect 会自动处理:
- 处理时间:约 15-30 分钟
- 状态变化:Processing → Ready to Submit
步骤 2: 添加测试信息
1. 登录 App Store Connect (https://appstoreconnect.apple.com)
2. 选择 App → TestFlight 标签页
3. 选择新上传的构建版本
4. 填写测试信息:
- What to Test: 测试重点说明
- App Description: 应用描述
- Feedback Email: 反馈邮箱
5. 提交内部测试 (Internal Testing)
步骤 3: 邀请测试用户
内部测试 (最多 100 人):
1. TestFlight → Internal Testing → 添加测试人员
2. 测试人员必须是 App Store Connect 用户
3. 无需 Apple 审核,立即可用
外部测试 (最多 10,000 人):
1. TestFlight → External Testing → 添加测试组
2. 输入测试用户邮箱
3. 需要 Apple 审核 (约 1-2 天)
4. 审核通过后,用户收到 TestFlight 邀请邮件
步骤 4: 测试用户安装
1. 测试用户从 App Store 下载 TestFlight App
2. 打开邀请邮件中的链接,或输入邀请码
3. 在 TestFlight 中安装测试版本
4. 应用旁会显示橙色圆点,表示是测试版本
11.9.6 一键 TestFlight 部署脚本
#!/bin/bash
# deploy-testflight.sh - iOS TestFlight 一键部署脚本
set -e
# 配置
PROJECT_PATH="$HOME/coding/qiudl/new-ai-proj/AI-Proj-iOS"
PROJECT_NAME="AI-Proj-iOS"
SCHEME="AI-Proj-iOS"
ARCHIVE_PATH="$HOME/Desktop/${PROJECT_NAME}.xcarchive"
EXPORT_PATH="$HOME/Desktop/${PROJECT_NAME}-Export"
echo "=== iOS TestFlight 部署 ==="
# 1. 更新代码
echo "📥 更新代码..."
cd "$PROJECT_PATH"
git pull origin main
# 2. 获取版本号
VERSION=$(xcodebuild -showBuildSettings -project "${PROJECT_NAME}.xcodeproj" -scheme "$SCHEME" 2>/dev/null | grep "MARKETING_VERSION" | head -1 | awk '{print $3}')
BUILD=$(xcodebuild -showBuildSettings -project "${PROJECT_NAME}.xcodeproj" -scheme "$SCHEME" 2>/dev/null | grep "CURRENT_PROJECT_VERSION" | head -1 | awk '{print $3}')
echo "📦 版本: $VERSION (Build $BUILD)"
# 3. 构建 Archive
echo "🔨 构建 Archive..."
xcodebuild -project "${PROJECT_NAME}.xcodeproj" \
-scheme "$SCHEME" \
-configuration Release \
-archivePath "$ARCHIVE_PATH" \
archive
# 4. 导出 IPA
echo "📤 导出 IPA..."
xcodebuild -exportArchive \
-archivePath "$ARCHIVE_PATH" \
-exportPath "$EXPORT_PATH" \
-exportOptionsPlist "$PROJECT_PATH/ExportOptions.plist"
echo ""
echo "✅ 构建完成!"
echo ""
echo "下一步:"
echo "1. 打开 Xcode Organizer: xed -b com.apple.dt.Xcode"
echo "2. 选择 Archive → Distribute App → App Store Connect"
echo "3. 或使用命令行上传:"
echo " xcrun altool --upload-app -f $EXPORT_PATH/${PROJECT_NAME}.ipa -t ios -u YOUR_APPLE_ID -p @keychain:AC_PASSWORD"
11.9.7 TestFlight 部署与 req skill 集成
在 req skill 中,iOS TestFlight 部署命令:
/req deploy REQ-ID --platform ios --env testflight
执行步骤:
1. SSH 到 cn-dev 更新代码
2. 执行 Archive 构建
3. 上传到 App Store Connect
4. 在 TestFlight 添加测试信息
5. 邀请测试用户
6. 确认测试用户可安装后,标记部署完成
11.10 iOS 部署与 req skill 集成
在 req skill 中,iOS 项目的 /req deploy 命令应执行:
/req deploy REQ-ID --platform ios [--env <environment>]
环境选项:
- 无参数或 --env dev: 直接安装到开发设备 (cn-dev)
- --env testflight: 发布到 TestFlight 内测
执行步骤 (开发安装):
1. 检查本机代码是否已提交
2. SSH 到 cn-dev 执行 git pull
3. 提示用户在 cn-dev 上打开 Xcode 构建并安装
4. 用户确认安装完成后,标记部署任务完成
执行步骤 (TestFlight):
1. 检查本机代码是否已提交
2. SSH 到 cn-dev 执行 git pull
3. 构建 Archive 并导出 IPA
4. 上传到 App Store Connect
5. 配置 TestFlight 测试信息
6. 邀请测试用户
7. 确认测试用户可安装后,标记部署完成
iOS 项目标准工作流:
开发测试流程:
/req test REQ-ID
↓
本机代码验证通过
↓
/req deploy REQ-ID --platform ios
↓
(SSH 到 cn-dev 更新代码)
↓
(在 cn-dev 上 Xcode 安装到 iPhone)
↓
用户验证 App 功能
↓
/req done REQ-ID
内测分发流程:
/req test REQ-ID
↓
本机代码验证通过
↓
/req deploy REQ-ID --platform ios --env testflight
↓
(构建 Archive + 上传 App Store Connect)
↓
(TestFlight 配置 + 邀请测试用户)
↓
测试用户验证 App 功能
↓
/req done REQ-ID
11.11 iOS 常见问题补充
Q5: Archive 构建失败 - 签名问题
# 检查签名配置
security find-identity -v -p codesigning
# 解锁钥匙串
security unlock-keychain -p "your-password" ~/Library/Keychains/login.keychain-db
# 检查 Provisioning Profile
ls ~/Library/MobileDevice/Provisioning\ Profiles/
Q6: 上传到 App Store Connect 失败
# 验证 IPA 格式
xcrun altool --validate-app -f /path/to/app.ipa -t ios -u YOUR_APPLE_ID -p @keychain:AC_PASSWORD
# 常见错误:
# - Invalid Binary: 检查 Info.plist 配置
# - Missing Icon: 确保所有尺寸的 App Icon 都存在
# - Provisioning Profile: 确保使用 App Store 类型的 Profile
Q7: TestFlight 处理时间过长
正常处理时间: 15-30 分钟
如果超过 1 小时:
1. 检查 App Store Connect 状态
2. 可能正在进行额外审核
3. 联系 Apple Developer Support
12. Android 应用部署
12.1 部署概述
Android 应用部署通过连接到 fuxing 电脑 进行真机安装,使用 ADB (Android Debug Bridge) 将 APK 安装到连接的 Android 设备。
部署流程:
本机代码提交
↓
SSH 到 fuxing 电脑
↓
git pull 更新代码
↓
构建 APK
↓
通过 ADB 安装到 Android 设备
12.2 服务器信息
| 配置项 | 值 |
|---|---|
| 服务器别名 | fuxing |
| IP 地址 | 100.90.190.119 (Tailscale VPN) |
| 用户名 | (根据实际配置) |
| 项目路径 | (根据实际项目位置) |
12.3 SSH 配置
确保 ~/.ssh/config 包含以下配置:
Host fuxing
HostName 100.90.190.119
User <username>
IdentityFile ~/.ssh/<your-key>
IdentitiesOnly yes
ServerAliveInterval 30
ServerAliveCountMax 6
12.4 部署步骤
步骤 1: 确保本机代码已提交
# 检查是否有未提交的更改
cd /path/to/android-project
git status
# 如有更改,提交并推送
git add -A
git commit -m "feat(Android): 功能描述"
git push origin main
步骤 2: SSH 到 fuxing 并更新代码
# SSH 连接到 fuxing
ssh fuxing
# 进入 Android 项目目录
cd /path/to/android-project
# 拉取最新代码
git pull origin main
# 确认代码已更新
git log -1 --oneline
步骤 3: 构建 APK
# 在 fuxing 上构建 APK
cd /path/to/android-project
# 使用 Gradle 构建 debug APK
./gradlew assembleDebug
# 或构建 release APK
./gradlew assembleRelease
# APK 输出路径
# Debug: app/build/outputs/apk/debug/app-debug.apk
# Release: app/build/outputs/apk/release/app-release.apk
步骤 4: 通过 ADB 安装到 Android 设备
# 检查已连接的 Android 设备
adb devices
# 如果有多个设备,指定设备 ID
adb -s <device-id> install -r app/build/outputs/apk/debug/app-debug.apk
# 单设备直接安装(-r 表示替换已有应用)
adb install -r app/build/outputs/apk/debug/app-debug.apk
# 安装成功后启动应用
adb shell am start -n <package-name>/<activity-name>
12.5 一键部署命令
从本机一键执行部署流程:
# 1. 推送本机代码
cd /path/to/android-project
git add -A && git commit -m "feat(Android): 更新" && git push origin main
# 2. SSH 到 fuxing 执行部署
ssh fuxing "cd /path/to/android-project && git pull origin main && ./gradlew assembleDebug && adb install -r app/build/outputs/apk/debug/app-debug.apk && echo '✅ Android 应用已安装'"
12.6 验证安装
安装完成后验证:
- App 启动检查:确保 App 能正常启动
- 登录功能:测试登录是否正常
- 新功能验证:测试本次部署的新功能
- API 连接:确保 App 能正确连接到后端 API
12.7 常见问题
Q1: SSH 连接超时
# 检查 Tailscale 状态
tailscale status
# 确认 fuxing 电脑在线 (100.90.190.119)
ping 100.90.190.119
Q2: ADB 设备未识别
# 检查 USB 调试是否已开启
# Android 设备上:设置 → 开发者选项 → USB 调试
# 重启 ADB 服务
adb kill-server
adb start-server
# 重新检查设备
adb devices
# 如果显示 unauthorized,需要在手机上允许调试
Q3: Gradle 构建失败
# 清理构建缓存
./gradlew clean
# 重新构建
./gradlew assembleDebug --stacktrace
Q4: APK 安装失败
# 卸载旧版本后重新安装
adb uninstall <package-name>
adb install app/build/outputs/apk/debug/app-debug.apk
# 检查签名问题
# 确保 debug/release APK 使用正确的签名
12.8 Android 部署与 req skill 集成
在 req skill 中,Android 项目的 /req deploy 命令应执行:
/req deploy REQ-ID --platform android
执行步骤:
1. 检查本机代码是否已提交
2. SSH 到 fuxing (100.90.190.119) 执行 git pull
3. 构建 APK (./gradlew assembleDebug)
4. 通过 ADB 安装到连接的 Android 设备
5. 用户确认安装完成后,标记部署任务完成
Android 项目标准工作流:
/req test REQ-ID
↓
本机代码验证通过
↓
/req deploy REQ-ID --platform android
↓
(SSH 到 fuxing 100.90.190.119)
↓
(构建 APK 并通过 ADB 安装)
↓
用户验证 App 功能
↓
/req done REQ-ID
变更记录
| 版本 | 日期 | 变更内容 | 变更人 |
|---|---|---|---|
| V1.2 | 2026-01-30 | 新增 Android 应用部署章节(Section 12),支持通过 fuxing 电脑 (100.90.190.119) 部署到 Android 设备 | Claude + qiudl |
| V1.1 | 2026-01-29 | 新增 iOS 应用部署章节(Section 11),支持通过 cn-dev 部署到 iPhone | Claude + qiudl |
| V1.0 | 2026-01-26 | 从 req skill 拆分,创建独立的 req-deploy 技能 | Claude + qiudl |