- 重命名 plugins/ → skills/,个人插件迁移到 skills-personal/(gitignore) - 更新 generate-marketplace.py 支持 config 读取和 skills-personal 扫描 - 新增 claude-config.yaml(技能启用/禁用 + MCP 配置) - 新增 init.sh(交互式 MCP 初始化,支持 stdio/SSE 模式) - 新增 CLAUDE.md 项目说明 - 重写 README.md 反映新结构 - 删除过时脚本:PUSH.sh、generate-marketplace.sh、convert-skills.sh Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
247 lines
7.5 KiB
Markdown
247 lines
7.5 KiB
Markdown
# 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'
|
||
```
|