diff --git a/.trae/rules/project_rules.md b/.trae/rules/project_rules.md new file mode 100644 index 0000000..79176ae --- /dev/null +++ b/.trae/rules/project_rules.md @@ -0,0 +1,23 @@ +# 项目规则 + +## Git 仓库信息 + +| 项目 | 远程地址 | 分支 | +|------|---------|------| +| 主仓库 (miniapp-api) | `https://git.dxz99wyr.cn/Superuser/miniapp-api.git` | master | +| miniapp 子模块 | `https://git.dxz99wyr.cn/Superuser/miniapp-web.git` | master | +| backend 子模块 | backend 目录 | - | + +## Git 凭据 + +- 用户名: `Superuser` +- 密码: `Admin@123` +- 凭据已存入 git credential store,无需手动输入 + +## Git 推送命令 + +推送时需要关闭 SSL 验证(服务器 SSL 证书问题): + +```bash +git -c http.sslVerify=false push origin master +``` diff --git a/CI_CD_SPEC.md b/CI_CD_SPEC.md new file mode 100644 index 0000000..3a67b26 --- /dev/null +++ b/CI_CD_SPEC.md @@ -0,0 +1,560 @@ +# 权益小助手 - CI/CD 流程规范 + +## 项目概述 + +- **项目名称**: 权益小助手 (QuanYiXiaoZhuShou) +- **项目类型**: 微信小程序 + Node.js 后端 +- **当前版本**: v0.1.0 +- **Git 仓库**: https://git.dxz99wyr.cn/Superuser/miniapp-api + +## 项目结构 + +``` +QuanYiXiaoZhuShou/ +├── backend/ # Node.js 后端服务 +│ ├── src/ # 源代码 +│ ├── Dockerfile # Docker 构建文件 +│ ├── docker-compose.yml # Docker Compose 配置 +│ ├── nginx-api.conf # Nginx 反向代理配置 +│ └── package.json # 依赖管理 +├── miniapp/ # 微信小程序前端 +│ ├── pages/ # 页面代码 +│ ├── utils/ # 工具函数 +│ └── app.js # 小程序入口 +└── test/ # 测试相关 +``` + +## 技术栈 + +### 后端 (Backend) +- **Runtime**: Node.js >= 18.0.0 +- **Framework**: Express.js 4.18.2 +- **Database**: MongoDB 7.0 +- **Process Manager**: PM2 +- **Container**: Docker + Docker Compose +- **Web Server**: Nginx (反向代理) + +### 前端 (Miniapp) +- **Platform**: 微信小程序 +- **Language**: JavaScript +- **Build Tool**: 微信开发者工具 + +### 服务器环境 +- **OS**: Ubuntu/Debian (推测) +- **Server IP**: 8.136.137.59 +- **Domain**: api-miniapp.dxz99wyr.cn +- **SSL**: 已配置 +- **Deployment Path**: /var/www/quanyixiaozhushou-app + +## 当前部署状态 + +### 服务器部署方式 +当前使用 **Docker** 容器部署,包含两个容器: + +| 容器名称 | 服务 | 端口 | 状态 | +|---------|------|------|------| +| `quanyixiaozhushou-app` | Node.js 后端 | 3000 | 运行中 | +| `quanyixiaozhushou-mongo` | MongoDB 7.0 | 27018 | 运行中 | + +```bash +# 查看容器状态 +docker ps + +# 查看后端日志 +docker logs quanyixiaozhushou-app + +# 查看 MongoDB 日志 +docker logs quanyixiaozhushou-mongo +``` + +### 环境变量 (生产环境) +```env +PORT=3000 +NODE_ENV=production +WECHAT_APPID=wxa83262674846ca1a +WECHAT_APPSECRET=c40e9d356438f92d10091a115ee50172 +MONGODB_URI=mongodb://localhost:27017/quanyixiaozhushou +JWT_SECRET=your_jwt_secret_key_here_change_in_production +JWT_EXPIRES_IN=7d +LOG_LEVEL=info +``` + +## CI/CD 流程设计 + +### 1. Git 工作流 + +``` +[Developer] → feature branch → Pull Request → [Code Review] → merge to master → [CI/CD Pipeline] → Deploy +``` + +### 2. 分支策略 + +| 分支 | 用途 | 保护规则 | +|------|------|----------| +| master | 生产环境分支 | 禁止直接推送,需 PR | +| develop | 开发环境分支 | 需 PR | +| feature/* | 功能开发 | 自由推送 | +| hotfix/* | 紧急修复 | 需 PR 到 master | + +### 3. CI/CD Pipeline 流程 + +```mermaid +graph TD + A[Git Push/PR] --> B[Checkout Code] + B --> C[Install Dependencies] + C --> D[Run Tests] + D --> E[Lint Check] + E --> F[Build Docker Image] + F --> G[Push to Registry] + G --> H[Deploy to Server] + H --> I[Health Check] + I --> J[Notify] +``` + +## 详细 CI/CD 配置 + +### Stage 1: 代码检出 (Checkout) + +```yaml +# .github/workflows/ci-cd.yml +name: CI/CD Pipeline + +on: + push: + branches: [ master, develop ] + pull_request: + branches: [ master ] + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + repository: https://git.dxz99wyr.cn/Superuser/miniapp-api + token: ${{ secrets.GIT_ACCESS_TOKEN }} +``` + +### Stage 2: 依赖安装与测试 + +```yaml + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + cache-dependency-path: backend/package-lock.json + + - name: Install backend dependencies + working-directory: ./backend + run: npm ci + + - name: Run backend tests + working-directory: ./backend + run: npm test + continue-on-error: true # 如果没有测试,不阻塞流程 + + - name: Run backend lint + working-directory: ./backend + run: npm run lint + continue-on-error: true +``` + +### Stage 3: Docker 构建 + +```yaml + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io # 或你的私有仓库 + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: ./backend + push: true + tags: | + ghcr.io/${{ github.repository }}/backend:${{ github.sha }} + ghcr.io/${{ github.repository }}/backend:latest + cache-from: type=gha + cache-to: type=gha,mode=max +``` + +### Stage 4: 部署到服务器 + +```yaml + - name: Deploy to server + uses: appleboy/ssh-action@v1.0.0 + with: + host: 8.136.137.59 + username: root + key: ${{ secrets.SSH_PRIVATE_KEY }} + script: | + # 拉取最新镜像 + docker pull ghcr.io/${{ github.repository }}/backend:latest + + # 停止旧容器 + docker stop quanyi-backend || true + docker rm quanyi-backend || true + + # 启动新容器 + docker run -d \ + --name quanyi-backend \ + --restart unless-stopped \ + -p 3000:3000 \ + -e PORT=3000 \ + -e NODE_ENV=production \ + -e WECHAT_APPID=${{ secrets.WECHAT_APPID }} \ + -e WECHAT_APPSECRET=${{ secrets.WECHAT_APPSECRET }} \ + -e MONGODB_URI=${{ secrets.MONGODB_URI }} \ + -e JWT_SECRET=${{ secrets.JWT_SECRET }} \ + -v /var/www/quanyixiaozhushou-app/public/uploads:/app/public/uploads \ + ghcr.io/${{ github.repository }}/backend:latest + + # 健康检查 + sleep 10 + curl -f http://localhost:3000/health || exit 1 +``` + +## 环境变量配置 + +### GitHub Secrets 需要配置 + +| Secret Name | Description | Example | +|-------------|-------------|---------| +| `GIT_ACCESS_TOKEN` | Git 仓库访问令牌 | 用于拉取 `https://git.dxz99wyr.cn/Superuser/miniapp-api` | +| `SSH_PRIVATE_KEY` | 服务器 SSH 私钥 | `-----BEGIN OPENSSH PRIVATE KEY-----...` | +| `WECHAT_APPID` | 微信小程序 AppID | `wxa83262674846ca1a` | +| `WECHAT_APPSECRET` | 微信小程序 AppSecret | `c40e9d356438f92d10091a115ee50172` | +| `MONGODB_URI` | MongoDB 连接字符串 | `mongodb://localhost:27017/quanyixiaozhushou` | +| `JWT_SECRET` | JWT 密钥 | `your_jwt_secret_key` | + +## 部署脚本 (服务器端) + +### 1. 初始化脚本 (首次部署) + +```bash +#!/bin/bash +# deploy-init.sh + +set -e + +PROJECT_DIR="/var/www/quanyixiaozhushou-app" +BACKUP_DIR="/var/backups/quanyixiaozhushou" + +# 创建目录 +mkdir -p $PROJECT_DIR +mkdir -p $BACKUP_DIR +mkdir -p $PROJECT_DIR/public/uploads +mkdir -p $PROJECT_DIR/public/avatars + +# 安装 Docker (如果未安装) +if ! command -v docker &> /dev/null; then + curl -fsSL https://get.docker.com | sh + systemctl enable docker + systemctl start docker +fi + +# 安装 Docker Compose +if ! command -v docker-compose &> /dev/null; then + curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + chmod +x /usr/local/bin/docker-compose +fi + +echo "初始化完成" +``` + +### 2. 部署脚本 (日常更新) + +```bash +#!/bin/bash +# deploy.sh + +set -e + +IMAGE_TAG=${1:-latest} +PROJECT_DIR="/var/www/quanyixiaozhushou-app" +BACKUP_DIR="/var/backups/quanyixiaozhushou" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) + +echo "=== 开始部署 ===" +echo "镜像标签: $IMAGE_TAG" + +# 1. 备份当前数据 +echo "[1/5] 备份当前数据..." +mkdir -p $BACKUP_DIR/$TIMESTAMP +cp -r $PROJECT_DIR/public/uploads $BACKUP_DIR/$TIMESTAMP/ 2>/dev/null || true +mongodump --db quanyixiaozhushou --out $BACKUP_DIR/$TIMESTAMP/ 2>/dev/null || true + +# 2. 拉取最新镜像 +echo "[2/5] 拉取最新镜像..." +docker pull ghcr.io/your-repo/quanyixiaozhushou-backend:$IMAGE_TAG + +# 3. 停止旧容器 +echo "[3/5] 停止旧容器..." +docker stop quanyi-backend 2>/dev/null || true +docker rm quanyi-backend 2>/dev/null || true + +# 4. 启动新容器 +echo "[4/5] 启动新容器..." +docker run -d \ + --name quanyi-backend \ + --restart unless-stopped \ + -p 3000:3000 \ + -e PORT=3000 \ + -e NODE_ENV=production \ + -e WECHAT_APPID=$WECHAT_APPID \ + -e WECHAT_APPSECRET=$WECHAT_APPSECRET \ + -e MONGODB_URI=$MONGODB_URI \ + -e JWT_SECRET=$JWT_SECRET \ + -v $PROJECT_DIR/public/uploads:/app/public/uploads \ + -v $PROJECT_DIR/public/avatars:/app/public/avatars \ + ghcr.io/your-repo/quanyixiaozhushou-backend:$IMAGE_TAG + +# 5. 健康检查 +echo "[5/5] 健康检查..." +sleep 5 + +MAX_RETRIES=10 +RETRY_COUNT=0 + +while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do + if curl -f -s http://localhost:3000/health > /dev/null; then + echo "✅ 服务健康检查通过" + break + fi + + RETRY_COUNT=$((RETRY_COUNT + 1)) + echo "等待服务启动... ($RETRY_COUNT/$MAX_RETRIES)" + sleep 3 +done + +if [ $RETRY_COUNT -eq $MAX_RETRIES ]; then + echo "❌ 健康检查失败,执行回滚..." + # 回滚逻辑 + docker stop quanyi-backend + docker rm quanyi-backend + # 启动上一个版本 + exit 1 +fi + +# 清理旧镜像 +docker image prune -f + +echo "=== 部署完成 ===" +echo "备份位置: $BACKUP_DIR/$TIMESTAMP" +``` + +## 健康检查端点 + +确保后端有以下健康检查端点: + +```javascript +// src/app.js +app.get('/health', (req, res) => { + res.status(200).json({ + status: 'ok', + timestamp: new Date().toISOString(), + version: process.env.npm_package_version || '1.0.0' + }); +}); +``` + +## 微信小程序 CI/CD + +### 自动上传脚本 + +```yaml +# .github/workflows/miniapp-deploy.yml +name: Miniapp Deploy + +on: + push: + branches: [ master ] + paths: + - 'miniapp/**' + +jobs: + deploy-miniapp: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Install miniprogram-ci + run: npm install -g miniprogram-ci + + - name: Upload to WeChat + working-directory: ./miniapp + run: | + miniprogram-ci upload \ + --pp ./ \ + --pkp ${{ secrets.WECHAT_PRIVATE_KEY }} \ + --appid ${{ secrets.WECHAT_APPID }} \ + --uv ${{ github.run_number }} \ + --enable-es6 true +``` + +## 监控与告警 + +### 1. 日志监控 + +```bash +# 查看实时日志 +docker logs -f quanyi-backend + +# 查看错误日志 +docker logs quanyi-backend 2>&1 | grep ERROR +``` + +### 进程监控 + +```bash +# Docker 容器监控 +docker stats quanyixiaozhushou-app + +# 进入容器调试 +docker exec -it quanyixiaozhushou-app sh +``` + +### 3. 告警规则 + +- 服务 5xx 错误率 > 1% +- 响应时间 > 2s +- 内存使用 > 80% +- CPU 使用 > 80% +- 磁盘使用 > 85% + +## 回滚策略 + +### 自动回滚条件 + +- 健康检查失败 +- 错误率突增 +- 部署后 5 分钟内服务不可用 + +### 回滚脚本 + +```bash +#!/bin/bash +# rollback.sh + +PREVIOUS_IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" | grep quanyixiaozhushou-backend | head -2 | tail -1) + +echo "回滚到上一个版本: $PREVIOUS_IMAGE" + +docker stop quanyi-backend +docker rm quanyi-backend +docker run -d \ + --name quanyi-backend \ + --restart unless-stopped \ + -p 3000:3000 \ + -e PORT=3000 \ + -e NODE_ENV=production \ + -v /var/www/quanyixiaozhushou-app/public/uploads:/app/public/uploads \ + $PREVIOUS_IMAGE + +echo "回滚完成" +``` + +## 数据库迁移 + +### MongoDB 迁移脚本 + +```javascript +// migrations/001_add_subscription_type.js +const mongoose = require('mongoose'); + +async function migrate() { + await mongoose.connect(process.env.MONGODB_URI); + + // 添加 type 字段到现有订阅记录 + await mongoose.connection.collection('usersubscriptions').updateMany( + { type: { $exists: false } }, + { $set: { type: 'version-update' } } + ); + + console.log('Migration completed'); + process.exit(0); +} + +migrate().catch(console.error); +``` + +## 安全检查清单 + +- [ ] 环境变量不提交到 Git +- [ ] 使用 secrets 管理敏感信息 +- [ ] Docker 镜像使用非 root 用户运行 +- [ ] 启用 HTTPS +- [ ] 配置防火墙规则 +- [ ] 定期更新依赖 +- [ ] 启用日志审计 +- [ ] 配置备份策略 + +## 附录 + +### A. 常用命令 + +```bash +# 查看容器状态 +docker ps + +# 查看容器日志 +docker logs quanyi-backend + +# 进入容器 +docker exec -it quanyi-backend sh + +# 重启容器 +docker restart quanyi-backend + +# 查看资源使用 +docker stats quanyi-backend +``` + +### B. 故障排查 + +```bash +# 服务无法启动 +docker logs quanyi-backend + +# MongoDB 连接失败 +docker exec -it quanyi-backend node -e "require('mongoose').connect(process.env.MONGODB_URI).then(() => console.log('OK')).catch(e => console.error(e))" + +# 端口占用 +netstat -tlnp | grep 3000 +``` + +### C. 联系方式与仓库信息 + +- **Git 仓库**: https://git.dxz99wyr.cn/Superuser/miniapp-api +- **服务器**: 8.136.137.59 +- **域名**: api-miniapp.dxz99wyr.cn +- **SSH 密钥**: D:\003_Project\小程序连接.pem + +### D. Git 仓库配置命令 + +```bash +# 添加远程仓库 +git remote add origin https://git.dxz99wyr.cn/Superuser/miniapp-api + +# 推送代码 +git push -u origin master + +# 拉取最新代码 +git pull origin master +``` diff --git a/backend b/backend index 8bab5d6..0ff5a02 160000 --- a/backend +++ b/backend @@ -1 +1 @@ -Subproject commit 8bab5d67b2ac16750691f1d3662c436b641a18a0 +Subproject commit 0ff5a02155ae1cfad1babc5a7ab99de86ec21bfe