# ═══════════════════════════════════════════════
# 🔺 Sovereign: TCS-0002∞ | Root: SYS-GLW-0001
# 📜 Copyright: 国作登字-2026-A-00037559
# ═══════════════════════════════════════════════
name: "🚀 铸渊 CD · 自动部署到 guanghulab.com"

# ━━━ 铸渊主权服务器部署 · ZY-SVR-002 ━━━
# 已从香港(150.109.76.244)迁移到新加坡(43.134.16.246)
# push 到 main → 校验 → rsync 同步全站到服务器 → 后端重启 → Nginx 配置 → Notion 通知
#
# 必需 GitHub Secrets（参考 brain/secrets-manifest.json）:
#   ZY_SERVER_HOST — 铸渊主权服务器 IP (43.134.16.246)
#   ZY_SERVER_USER — SSH 用户名
#   ZY_SERVER_KEY  — SSH 私钥（完整 PEM 内容）
#   ZY_SERVER_PATH — 网站根目录（/opt/zhuyuan）
#
# 可选 Secrets:
#   ZY_NOTION_TOKEN      — Notion 集成 token
#   ZY_NOTION_CHANGELOG_DB — Notion 变更日志数据库 ID

on:
  push:
    branches: [main]
    paths-ignore:
      - '.github/persona-brain/**'
      - 'broadcasts-outbox/**'
      - 'syslog-inbox/**'
      - 'syslog-processed/**'
      - 'signal-log/**'
      - 'dev-nodes/**'

  workflow_dispatch:

permissions:
  contents: read

jobs:

  # ═══════════════════════════════════════════════════════════════
  # Job 1: 部署前校验
  # ═══════════════════════════════════════════════════════════════
  validate:
    name: "🔍 部署前校验"
    runs-on: ubuntu-latest
    steps:
      - name: 📥 检出代码
        uses: actions/checkout@v4

      - name: 🟢 配置 Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: 📦 安装依赖（如需要）
        run: |
          if [ -f "package-lock.json" ] && grep -q '"glob"' package.json; then
            npm ci --ignore-scripts || npm install --ignore-scripts || echo "⚠️ 依赖安装失败，继续执行"
          fi

      - name: 🔍 HLI 契约校验
        run: |
          if [ -f "scripts/contract-check.js" ]; then
            echo "🔍 执行 HLI 契约校验..."
            node scripts/contract-check.js
          else
            echo "⏭️ scripts/contract-check.js 不存在，跳过 HLI 校验"
          fi

      - name: 📋 模块指纹检查
        run: |
          if [ -f "scripts/zhuyuan-module-protocol.js" ]; then
            echo "🔍 执行模块指纹检查..."
            node scripts/zhuyuan-module-protocol.js status
          else
            echo "⏭️ scripts/zhuyuan-module-protocol.js 不存在，跳过模块检查"
          fi

      - name: ✅ 校验汇总
        run: |
          echo "### ✅ 部署前校验通过" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "- HLI 契约校验: ✅" >> $GITHUB_STEP_SUMMARY
          echo "- 模块指纹检查: ✅" >> $GITHUB_STEP_SUMMARY
          echo "- 提交: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY

  # ═══════════════════════════════════════════════════════════════
  # Job 2: rsync 同步到服务器
  # ═══════════════════════════════════════════════════════════════
  deploy:
    name: "🚀 部署到服务器"
    needs: validate
    runs-on: ubuntu-latest
    steps:
      - name: 🔐 检查必需 Secrets
        run: |
          # ZY_SERVER_* 密钥（铸渊主权服务器 · 参考 brain/secrets-manifest.json）
          if [ -n "${{ secrets.ZY_SERVER_HOST }}" ]; then
            echo "SERVER_HOST=${{ secrets.ZY_SERVER_HOST }}" >> $GITHUB_ENV
            echo "SERVER_USER=${{ secrets.ZY_SERVER_USER }}" >> $GITHUB_ENV
            echo "SERVER_KEY<<KEYEOF" >> $GITHUB_ENV
            echo "${{ secrets.ZY_SERVER_KEY }}" >> $GITHUB_ENV
            echo "KEYEOF" >> $GITHUB_ENV
            echo "SERVER_PATH=${{ secrets.ZY_SERVER_PATH }}" >> $GITHUB_ENV
            echo "✅ 使用铸渊主权服务器密钥 (ZY_SERVER_*)"
          else
            echo "❌ 未配置服务器部署密钥"
            echo ""
            echo "请在仓库 Settings → Secrets and variables → Actions 中添加："
            echo "  ZY_SERVER_HOST — 铸渊主权服务器 IP (43.134.16.246)"
            echo "  ZY_SERVER_USER — SSH 用户名"
            echo "  ZY_SERVER_KEY  — SSH 私钥（完整 PEM 内容）"
            echo "  ZY_SERVER_PATH — 部署根目录 (/opt/zhuyuan)"
            echo ""
            echo "### ❌ 部署失败：缺少服务器部署密钥" >> $GITHUB_STEP_SUMMARY
            echo "请配置 ZY_SERVER_HOST / ZY_SERVER_USER / ZY_SERVER_KEY / ZY_SERVER_PATH" >> $GITHUB_STEP_SUMMARY
            exit 1
          fi

          # 验证必需字段
          MISSING=""
          if [ -z "${{ secrets.ZY_SERVER_HOST }}" ]; then MISSING="${MISSING} HOST"; fi
          if [ -z "${{ secrets.ZY_SERVER_USER }}" ]; then MISSING="${MISSING} USER"; fi
          if [ -z "${{ secrets.ZY_SERVER_KEY }}" ]; then MISSING="${MISSING} KEY"; fi
          if [ -z "${{ secrets.ZY_SERVER_PATH }}" ]; then MISSING="${MISSING} PATH"; fi
          if [ -n "$MISSING" ]; then
            echo "❌ 缺少必需密钥：${MISSING}"
            exit 1
          fi
          echo "✅ 所有必需 Secrets 已配置"

      - name: 📥 检出代码
        uses: actions/checkout@v4

      - name: 📦 确保本地 rsync 已安装
        run: |
          if ! command -v rsync &>/dev/null; then
            sudo apt-get update -qq && sudo apt-get install -y rsync
          fi
          rsync --version | head -1

      - name: 🔑 配置 SSH 连接
        run: |
          mkdir -p ~/.ssh
          echo "${{ env.SERVER_KEY }}" > ~/.ssh/deploy_key
          chmod 600 ~/.ssh/deploy_key
          ssh-keyscan -H "${{ env.SERVER_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null || {
            echo "⚠️ ssh-keyscan 失败，尝试使用 StrictHostKeyChecking=no 作为后备"
          }

      - name: 📦 确保远程服务器 rsync 已安装
        run: |
          echo "🔍 检查远程服务器 rsync..."
          ssh -i ~/.ssh/deploy_key ${{ env.SERVER_USER }}@${{ env.SERVER_HOST }} \
            "command -v rsync || { echo '⚠️ 远程服务器未安装 rsync，尝试安装...' && \
              (sudo apt-get update -qq && sudo apt-get install -y rsync 2>/dev/null || \
               sudo yum install -y rsync 2>/dev/null || \
               { echo '❌ 无法自动安装 rsync（可能缺少 sudo 权限）'; \
                 echo '请手动在服务器上安装: sudo apt-get install rsync 或 sudo yum install rsync'; \
                 exit 1; }); }"
          echo "✅ 远程服务器 rsync 检查完成"

      - name: 📁 确保远程部署目录存在
        run: |
          echo "🔍 检查远程部署目录..."
          ssh -i ~/.ssh/deploy_key \
            "${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}" \
            "mkdir -p '${{ env.SERVER_PATH }}'" || {
              echo "❌ 无法创建远程部署目录（SSH 连接失败或权限不足）"
              echo "请确认 ZY_SERVER_PATH 设置正确且 ZY_SERVER_USER 有写入权限"
              exit 1
            }
          echo "✅ 远程部署目录已就绪"

      - name: 🔒 部署前安全检查
        run: |
          if [ ! -f "docs/index.html" ]; then
            echo "❌ docs/index.html 不存在，中止部署以防清空生产环境"
            exit 1
          fi
          FILE_COUNT=$(find . -type f \
            -not -path './.git/*' \
            -not -path './.github/*' \
            -not -path '*/node_modules/*' \
            | wc -l)
          if [ "$FILE_COUNT" -lt 5 ]; then
            echo "❌ 仓库文件数异常（仅 ${FILE_COUNT} 个），中止部署"
            exit 1
          fi
          echo "✅ 仓库包含 ${FILE_COUNT} 个文件，安全检查通过"

      - name: 🚀 rsync 同步全站到服务器
        run: |
          echo "📡 开始同步全站到 ${{ env.SERVER_HOST }}:${{ env.SERVER_PATH }}"

          rsync -avz --delete-after \
            --exclude '.git' \
            --exclude '.github' \
            --exclude 'node_modules' \
            --exclude 'syslog-inbox' \
            --exclude 'syslog-processed' \
            --exclude 'broadcasts-outbox' \
            --exclude 'dev-nodes' \
            --exclude 'signal-log' \
            --exclude 'tests' \
            --exclude 'reports' \
            --exclude 'scripts' \
            --exclude 'guanghulab-main' \
            --exclude '*.bak' \
            --exclude '*.bak2' \
            --exclude '*_副本' \
            --exclude '*_副本/' \
            --exclude '*_副本.*' \
            --exclude '.DS_Store' \
            --exclude '.env' \
            --exclude 'package-lock.json' \
            --exclude 'tsconfig.json' \
            --exclude 'next.config.ts' \
            --exclude 'postcss.config.mjs' \
            --exclude 'jest.smoke.config.js' \
            --exclude 'ecosystem.config.js' \
            --exclude '.gitignore' \
            --exclude 'CNAME' \
            --exclude '*.zip' \
            -e "ssh -i ~/.ssh/deploy_key" \
            ./ \
            ${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}:${{ env.SERVER_PATH }}/

          echo "✅ 全站同步完成"

      - name: 🌐 注入生产环境标识
        run: |
          echo "🌐 Setting HOLOLAKE_ENV=production on server..."
          ssh -i ~/.ssh/deploy_key \
            "${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}" "
              DP='${{ env.SERVER_PATH }}'
              # Create environment config file for frontend detection
              echo '{\"env\":\"production\",\"domain\":\"guanghulab.com\",\"deployed_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"commit\":\"${{ github.sha }}\"}' > \"\$DP/docs/env.json\"
              echo '{\"env\":\"production\",\"domain\":\"guanghulab.com\",\"deployed_at\":\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\",\"commit\":\"${{ github.sha }}\"}' > \"\$DP/env.json\"
            "
          echo "✅ 环境标识已注入"

      - name: 📄 复制首页到站点根目录
        run: |
          echo "📄 复制 docs/index.html → 站点根目录 index.html"
          ssh -i ~/.ssh/deploy_key \
            "${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}" "
              cp '${{ env.SERVER_PATH }}/docs/index.html' '${{ env.SERVER_PATH }}/index.html'
              # 同步 docs 下的其他静态资源到根目录
              cp '${{ env.SERVER_PATH }}/docs/.nojekyll' '${{ env.SERVER_PATH }}/.nojekyll' 2>/dev/null || true
            "
          echo "✅ 首页已部署到根目录"

      - name: 🔗 模块路由别名（symlink 补全）
        continue-on-error: true
        run: |
          echo "🔗 创建模块路由别名..."
          ssh -i ~/.ssh/deploy_key \
            "${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}" "
              DP='${{ env.SERVER_PATH }}'

              # dashboard → docs/dashboard（仪表盘在 docs/ 子目录下）
              if [ -d \"\$DP/docs/dashboard\" ] && [ ! -e \"\$DP/dashboard\" ]; then
                ln -s \"\$DP/docs/dashboard\" \"\$DP/dashboard\"
                echo '✅ dashboard → docs/dashboard'
              elif [ -L \"\$DP/dashboard\" ]; then
                echo '✅ dashboard symlink 已存在'
              elif [ -d \"\$DP/dashboard\" ]; then
                echo '✅ dashboard 目录已存在'
              else
                echo '⚠️ docs/dashboard 不存在，跳过'
              fi

              # devboard → modules/devboard（开发者看板在 modules/ 子目录下）
              if [ -d \"\$DP/modules/devboard\" ] && [ ! -e \"\$DP/devboard\" ]; then
                ln -s \"\$DP/modules/devboard\" \"\$DP/devboard\"
                echo '✅ devboard → modules/devboard'
              elif [ -L \"\$DP/devboard\" ]; then
                echo '✅ devboard symlink 已存在'
              elif [ -d \"\$DP/devboard\" ]; then
                echo '✅ devboard 目录已存在'
              else
                echo '⚠️ modules/devboard 不存在，跳过'
              fi
            "
          echo "✅ 模块路由别名处理完成"

      - name: 🔧 后端服务部署
        continue-on-error: true
        run: |
          echo "🔧 检查并部署后端服务..."
          ssh -i ~/.ssh/deploy_key \
            "${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}" "
              # 检查 Node.js 和 pm2 是否可用
              if ! command -v node &>/dev/null; then
                echo '⏭️ Node.js 未安装，跳过后端部署'
                exit 0
              fi
              if ! command -v pm2 &>/dev/null; then
                echo '⏭️ pm2 未安装，跳过后端服务管理'
                exit 0
              fi

              # 部署 API 代理服务（AI 聊天代理，端口 3721）
              if [ -f '${{ env.SERVER_PATH }}/backend-integration/api-proxy.js' ]; then
                echo '📦 安装 API 代理依赖...'
                cd '${{ env.SERVER_PATH }}/backend-integration'
                npm install --production 2>/dev/null || echo '⚠️ api-proxy npm install 失败（可能无 package.json，继续）'
                echo '🔄 重启 API 代理服务...'
                export YUNWU_API_KEY='${{ secrets.ZY_LLM_API_KEY }}'
                export DEEPSEEK_API_KEY='${{ secrets.ZY_LLM_API_KEY }}'
                pm2 delete guanghulab-proxy 2>/dev/null || true
                YUNWU_API_KEY='${{ secrets.ZY_LLM_API_KEY }}' DEEPSEEK_API_KEY='${{ secrets.ZY_LLM_API_KEY }}' \
                  pm2 start api-proxy.js --name guanghulab-proxy --update-env 2>/dev/null || \
                  echo '⚠️ API 代理 pm2 启动失败'
              fi

              # 部署 backend 服务（Express API，端口 3000）
              if [ -f '${{ env.SERVER_PATH }}/backend/server.js' ]; then
                echo '📦 安装 backend 依赖...'
                cd '${{ env.SERVER_PATH }}/backend'
                npm install --production 2>/dev/null || echo '⚠️ backend npm install 失败'
                echo '🔄 重启 backend 服务...'
                pm2 restart guanghulab-backend 2>/dev/null || \
                  pm2 start server.js --name guanghulab-backend 2>/dev/null || \
                  echo '⚠️ backend pm2 启动失败'
              fi

              # 部署 status-board WebSocket 服务（端口 8080）
              if [ -f '${{ env.SERVER_PATH }}/status-board/mock-ws-server.js' ]; then
                echo '🔄 重启 WebSocket 服务...'
                cd '${{ env.SERVER_PATH }}/status-board'
                npm install --production 2>/dev/null || true
                pm2 restart guanghulab-ws 2>/dev/null || \
                  pm2 start mock-ws-server.js --name guanghulab-ws 2>/dev/null || \
                  echo '⚠️ WebSocket pm2 启动失败'
              fi

              # 部署 src HLI 中间层（端口 3001，对应 Nginx /api/v1/ 路由）
              # 注意：guanghulab-backend 已占用端口 3000，HLI 使用 3001 避免冲突
              if [ -f '${{ env.SERVER_PATH }}/src/index.js' ]; then
                echo '📦 安装 src 依赖...'
                cd '${{ env.SERVER_PATH }}'
                npm install --production 2>/dev/null || echo '⚠️ src npm install 失败'
                echo '🔄 重启 HLI 服务（端口 3001）...'
                pm2 delete guanghulab 2>/dev/null || true
                PORT=3001 pm2 start src/index.js --name guanghulab --update-env 2>/dev/null || \
                  echo '⚠️ src pm2 启动失败'
              fi

              # 部署 Persona Studio 后端服务（端口 3002）
              if [ -f '${{ env.SERVER_PATH }}/persona-studio/backend/server.js' ]; then
                echo '📦 安装 persona-studio 依赖...'
                cd '${{ env.SERVER_PATH }}/persona-studio/backend'
                npm install --production 2>/dev/null || echo '⚠️ persona-studio npm install 失败'
                echo '🔄 重启 persona-studio 服务...'
                export MODEL_API_KEY='${{ secrets.ZY_LLM_API_KEY }}'
                pm2 delete persona-studio 2>/dev/null || true
                MODEL_API_KEY='${{ secrets.ZY_LLM_API_KEY }}' \
                  pm2 start server.js --name persona-studio --update-env 2>/dev/null || \
                  echo '⚠️ persona-studio pm2 启动失败'
              fi

              pm2 save || echo '⚠️ pm2 save 失败，重启后进程可能不会自动启动'

              # 设置开机自启（仅首次需要，后续无操作）
              pm2 startup 2>/dev/null | grep -o 'sudo.*' | bash 2>/dev/null || true

              echo '✅ 后端服务部署完成'
            "

      - name: 🌐 更新 Nginx 配置
        continue-on-error: true
        run: |
          echo "🔧 检查 Nginx 配置..."
          ssh -i ~/.ssh/deploy_key \
            "${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}" "
              # 检查 Nginx 是否安装
              if ! command -v nginx &>/dev/null; then
                echo '⏭️ Nginx 未安装，跳过配置更新'
                exit 0
              fi

              NGINX_CHANGED=false

              # 一次性迁移：更新 root 路径（从旧的 status-board 子目录改为站点根目录）
              if grep -q 'root.*guanghulab/status-board' /etc/nginx/sites-available/default 2>/dev/null || \
                 grep -q 'root.*guanghulab/status-board' /etc/nginx/conf.d/*.conf 2>/dev/null; then
                echo '🔄 更新 Nginx root 路径（status-board → 站点根）...'
                sudo sed -i 's|root.*guanghulab/status-board[^;]*|root ${{ env.SERVER_PATH }}|g' \
                  /etc/nginx/sites-available/default 2>/dev/null || true
                sudo sed -i 's|root.*guanghulab/status-board[^;]*|root ${{ env.SERVER_PATH }}|g' \
                  /etc/nginx/conf.d/*.conf 2>/dev/null || true
                NGINX_CHANGED=true
                echo '✅ Nginx root 路径已更新（status-board 迁移）'
              fi

              # 一次性迁移：修正 root 路径（从旧残留 hololake-frontend 改为 guanghulab）
              # 根因：ZY-NGINX-ROOTFIX-2026-0325-001 · DEV-004 之之诊断
              if grep -q 'root.*/var/www/hololake-frontend' /etc/nginx/sites-available/default 2>/dev/null || \
                 grep -q 'root.*/var/www/hololake-frontend' /etc/nginx/conf.d/*.conf 2>/dev/null; then
                echo '🔄 更新 Nginx root 路径（hololake-frontend → guanghulab）...'
                sudo sed -i 's|root /var/www/hololake-frontend|root ${{ env.SERVER_PATH }}|g' \
                  /etc/nginx/sites-available/default 2>/dev/null || true
                sudo sed -i 's|root /var/www/hololake-frontend|root ${{ env.SERVER_PATH }}|g' \
                  /etc/nginx/conf.d/*.conf 2>/dev/null || true
                NGINX_CHANGED=true
                echo '✅ Nginx root 路径已更新（hololake-frontend → guanghulab）'
              fi

              # 验证 root 路径确实正确（防御性检查）
              if ! grep -q "root ${{ env.SERVER_PATH }}" /etc/nginx/conf.d/*.conf 2>/dev/null && \
                 ! grep -q "root ${{ env.SERVER_PATH }}" /etc/nginx/sites-available/default 2>/dev/null; then
                echo '⚠️ Nginx root 路径可能未正确设置，请手动检查'
              else
                echo '✅ Nginx root 路径正确，指向 ${{ env.SERVER_PATH }}'
              fi

              # 配置 API + WebSocket 反向代理
              if ! grep -rq 'location /api/' /etc/nginx/sites-available/ /etc/nginx/conf.d/ /etc/nginx/snippets/ 2>/dev/null; then
                echo '🔄 添加 API + WebSocket 反向代理...'
                sudo mkdir -p /etc/nginx/snippets
                # 注意：\$ 在本地 shell 中转义为 $，远程 shell 的单引号保护不再展开，
                # 最终写入文件的 Nginx 变量为 $host、$http_upgrade 等
                printf '%s\n' \
                  '# guanghulab 反向代理（由 CD 工作流自动生成）' \
                  '' \
                  '# AI 聊天 API 代理 → api-proxy.js 端口 3721（SSE 流式支持）' \
                  'location /api/chat {' \
                  '    proxy_pass http://127.0.0.1:3721/api/chat;' \
                  '    proxy_http_version 1.1;' \
                  '    proxy_set_header Host \$host;' \
                  '    proxy_set_header X-Real-IP \$remote_addr;' \
                  '    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;' \
                  '    proxy_set_header X-Forwarded-Proto \$scheme;' \
                  '    proxy_set_header Connection "";' \
                  '    proxy_buffering off;' \
                  '    proxy_cache off;' \
                  '    chunked_transfer_encoding on;' \
                  '    proxy_read_timeout 90s;' \
                  '    proxy_send_timeout 60s;' \
                  '}' \
                  '' \
                  'location /api/models {' \
                  '    proxy_pass http://127.0.0.1:3721/api/models;' \
                  '    proxy_http_version 1.1;' \
                  '    proxy_set_header Host \$host;' \
                  '    proxy_set_header X-Real-IP \$remote_addr;' \
                  '}' \
                  '' \
                  'location /api/health {' \
                  '    proxy_pass http://127.0.0.1:3721/api/health;' \
                  '    proxy_http_version 1.1;' \
                  '    proxy_set_header Host \$host;' \
                  '    proxy_set_header X-Real-IP \$remote_addr;' \
                  '}' \
                  '' \
                  '# Persona Studio API → persona-studio 后端端口 3002（含 CORS 跨域支持）' \
                  'location /api/ps/ {' \
                  '    add_header Access-Control-Allow-Origin * always;' \
                  '    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;' \
                  '    add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;' \
                  '    if (\$request_method = OPTIONS) {' \
                  '        return 204;' \
                  '    }' \
                  '    proxy_pass http://127.0.0.1:3002/api/ps/;' \
                  '    proxy_http_version 1.1;' \
                  '    proxy_set_header Host \$host;' \
                  '    proxy_set_header X-Real-IP \$remote_addr;' \
                  '    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;' \
                  '    proxy_set_header X-Forwarded-Proto \$scheme;' \
                  '    proxy_read_timeout 90s;' \
                  '}' \
                  '' \
                  '# Persona Studio 前端静态文件' \
                  'location /persona-studio/ {' \
                  '    proxy_pass http://127.0.0.1:3002/persona-studio/;' \
                  '    proxy_http_version 1.1;' \
                  '    proxy_set_header Host \$host;' \
                  '    proxy_set_header X-Real-IP \$remote_addr;' \
                  '}' \
                  '' \
                  '# 其他 API → Express 后端端口 3000' \
                  'location /api/ {' \
                  '    proxy_pass http://127.0.0.1:3000/api/;' \
                  '    proxy_http_version 1.1;' \
                  '    proxy_set_header Host \$host;' \
                  '    proxy_set_header X-Real-IP \$remote_addr;' \
                  '    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;' \
                  '    proxy_set_header X-Forwarded-Proto \$scheme;' \
                  '    proxy_cache_bypass \$http_upgrade;' \
                  '}' \
                  '' \
                  '# Persona Studio WebSocket → 预览进度推送端口 3002' \
                  'location /ws/preview {' \
                  '    proxy_pass http://127.0.0.1:3002;' \
                  '    proxy_http_version 1.1;' \
                  '    proxy_set_header Upgrade \$http_upgrade;' \
                  '    proxy_set_header Connection \"Upgrade\";' \
                  '    proxy_set_header Host \$host;' \
                  '    proxy_set_header X-Real-IP \$remote_addr;' \
                  '    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;' \
                  '    proxy_read_timeout 86400;' \
                  '}' \
                  '' \
                  '# WebSocket 反向代理 → 看板实时推送端口 8080' \
                  'location /ws {' \
                  '    proxy_pass http://127.0.0.1:8080;' \
                  '    proxy_http_version 1.1;' \
                  '    proxy_set_header Upgrade \$http_upgrade;' \
                  '    proxy_set_header Connection \"Upgrade\";' \
                  '    proxy_set_header Host \$host;' \
                  '    proxy_set_header X-Real-IP \$remote_addr;' \
                  '    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;' \
                  '    proxy_read_timeout 86400;' \
                  '}' \
                  | sudo tee /etc/nginx/snippets/guanghulab-proxy.conf > /dev/null

                # 在 server 块中加入 include 指令（仅搜索 sites-available 避免 symlink 重复）
                NGINX_MAIN=\$(grep -rl 'server_name' /etc/nginx/sites-available/ 2>/dev/null | head -1)
                if [ -z \"\$NGINX_MAIN\" ]; then
                  NGINX_MAIN='/etc/nginx/sites-available/default'
                fi
                if [ -f \"\$NGINX_MAIN\" ] && ! grep -q 'guanghulab-proxy' \"\$NGINX_MAIN\" 2>/dev/null; then
                  sudo sed -i '/server_name/a\\    include /etc/nginx/snippets/guanghulab-proxy.conf;' \"\$NGINX_MAIN\" 2>/dev/null && \
                    NGINX_CHANGED=true && echo '✅ 反向代理已自动配置' || \
                    echo '⚠️ 自动配置失败，请手动在 Nginx server 块中加入: include /etc/nginx/snippets/guanghulab-proxy.conf;'
                fi
              else
                echo '✅ API 反向代理已存在，无需修改'
              fi

              # 补建 _shared 目录（沙盒共享资源）
              if [ ! -d /var/www/_shared ]; then
                sudo mkdir -p /var/www/_shared
                sudo chmod 755 /var/www/_shared
                echo '✅ _shared 目录已创建'
              fi

              # 沙盒 alias 路由补充（DEV-004, DEV-005）
              # 根因：ZY-NGINX-ROOTFIX-2026-0325-001 · 沙盒模块需通过域名访问
              SANDBOX_CONF='/etc/nginx/snippets/guanghulab-sandbox.conf'
              if [ ! -f \"\$SANDBOX_CONF\" ]; then
                printf '%s\n' \
                  '# guanghulab 沙盒路由（由 CD 工作流自动生成）' \
                  '' \
                  '# DEV-004 之之 · 沙盒路由' \
                  'location /DEV-004/ {' \
                  '    alias /var/www/DEV-004/;' \
                  '    index index.html;' \
                  '    try_files \$uri \$uri/ =404;' \
                  '}' \
                  '' \
                  '# DEV-005 小草莓 · 沙盒路由' \
                  'location /DEV-005/ {' \
                  '    alias /var/www/DEV-005/;' \
                  '    index index.html;' \
                  '    try_files \$uri \$uri/ =404;' \
                  '}' \
                  | sudo tee \"\$SANDBOX_CONF\" > /dev/null

                # 在 server 块中加入 sandbox include 指令
                NGINX_MAIN=\$(grep -rl 'server_name' /etc/nginx/sites-available/ 2>/dev/null | head -1)
                if [ -z \"\$NGINX_MAIN\" ]; then
                  NGINX_MAIN='/etc/nginx/sites-available/default'
                fi
                if [ -f \"\$NGINX_MAIN\" ] && ! grep -q 'guanghulab-sandbox' \"\$NGINX_MAIN\" 2>/dev/null; then
                  sudo sed -i '/server_name/a\\    include /etc/nginx/snippets/guanghulab-sandbox.conf;' \"\$NGINX_MAIN\" 2>/dev/null && \
                    NGINX_CHANGED=true && echo '✅ 沙盒路由已自动配置' || \
                    echo '⚠️ 沙盒路由自动配置失败，请手动添加'
                fi
              else
                echo '✅ 沙盒路由配置已存在'
              fi

              # 如果有变更，验证并重新加载 Nginx
              if [ \"\$NGINX_CHANGED\" = true ]; then
                sudo nginx -t && sudo systemctl reload nginx && echo '✅ Nginx 配置已重新加载' || \
                  echo '⚠️ Nginx 配置验证失败，请手动检查'
              fi
            "

      - name: 🔍 验证部署
        run: |
          ssh -i ~/.ssh/deploy_key \
            ${{ env.SERVER_USER }}@${{ env.SERVER_HOST }} \
            "echo '✅ 服务器连接正常' && \
             echo '--- 站点根目录 ---' && \
             ls -la ${{ env.SERVER_PATH }}/ | head -30 && \
             echo '--- docs/ ---' && \
             ls ${{ env.SERVER_PATH }}/docs/ 2>/dev/null || echo '(docs/ 不存在)' && \
             echo '--- status-board/ ---' && \
             ls ${{ env.SERVER_PATH }}/status-board/ 2>/dev/null || echo '(status-board/ 不存在)' && \
             echo '--- cost-control/ ---' && \
             ls ${{ env.SERVER_PATH }}/cost-control/ 2>/dev/null || echo '(cost-control/ 不存在)' && \
             echo '--- devboard/ ---' && \
             ls ${{ env.SERVER_PATH }}/devboard/ 2>/dev/null || echo '(devboard/ 不存在)' && \
             echo '--- persona-studio/ ---' && \
             ls ${{ env.SERVER_PATH }}/persona-studio/ 2>/dev/null || echo '(persona-studio/ 不存在)'"

      - name: 🏥 部署后冒烟测试
        continue-on-error: true
        run: |
          echo "🏥 部署后全模块冒烟测试..."
          ssh -i ~/.ssh/deploy_key \
            "${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}" "
              DP='${{ env.SERVER_PATH }}'
              PASSED=0
              FAILED=0
              RESULTS=''

              check_module() {
                local name=\$1
                local path=\$2
                if [ -f \"\$DP/\$path/index.html\" ] || [ -f \"\$DP/\$path/index.htm\" ]; then
                  PASSED=\$((PASSED+1))
                  RESULTS=\"\${RESULTS}✅ \${name} (\${path}/index.html)\n\"
                elif [ -d \"\$DP/\$path\" ]; then
                  PASSED=\$((PASSED+1))
                  RESULTS=\"\${RESULTS}⚠️ \${name} (目录存在，无 index.html)\n\"
                else
                  FAILED=\$((FAILED+1))
                  RESULTS=\"\${RESULTS}❌ \${name} (\${path}/ 不存在)\n\"
                fi
              }

              check_module '主站首页' 'docs'
              check_module '系统状态看板' 'status-board'
              check_module '成本控制' 'cost-control'
              check_module '开发者看板' 'devboard'
              check_module '光湖集成壳' 'app'
              check_module 'Persona Studio' 'persona-studio'
              check_module '后端服务' 'backend'
              check_module '用户中心' 'm05-user-center'
              check_module '对话界面' 'm07-dialogue-ui'
              check_module '云服务' 'm10-cloud'
              check_module '模块管理' 'm11-module'
              check_module '云盘' 'm15-cloud-drive'
              check_module '登录' 'm01-login'
              check_module '健康检查' 'm18-health-check'
              check_module '冷启动' 'coldstart'
              check_module '仪表盘' 'dashboard'
              check_module '门户' 'portal'
              check_module '通知' 'notification'
              check_module '帮助中心' 'help-center'
              check_module '前端' 'frontend'

              echo ''
              printf \"\$RESULTS\"
              echo ''
              echo \"━━━ 冒烟测试结果：\${PASSED} 通过 / \${FAILED} 失败 ━━━\"

              # 写入部署状态文件
              TIMESTAMP=\$(date -u '+%Y-%m-%dT%H:%M:%SZ')
              if command -v jq &>/dev/null; then
                jq -n --arg ts \"\$TIMESTAMP\" --arg commit \"${{ github.sha }}\" \
                  --argjson passed \"\$PASSED\" --argjson failed \"\$FAILED\" \
                  '{last_deploy: \$ts, commit: \$commit, modules_passed: \$passed, modules_failed: \$failed}' \
                  > \"\$DP/data/deploy-status.json\" 2>/dev/null || true
              else
                printf '{\"last_deploy\":\"%s\",\"commit\":\"%s\",\"modules_passed\":%d,\"modules_failed\":%d}' \
                  \"\$TIMESTAMP\" \"${{ github.sha }}\" \"\$PASSED\" \"\$FAILED\" \
                  > \"\$DP/data/deploy-status.json\" 2>/dev/null || true
              fi
            "
          echo "✅ 冒烟测试完成"

      - name: 👤 人类使用侧验证
        continue-on-error: true
        run: |
          echo "👤 人类使用侧验证（核心！系统测跑通 ≠ 人类测跑通）..."
          echo "等待 10 秒让服务启动..."
          sleep 10

          HUMAN_CHECK_PASSED=0
          HUMAN_CHECK_FAILED=0

          # 验证主站可访问
          HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 \
            "http://${{ env.SERVER_HOST }}" 2>/dev/null || echo "000")
          if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "301" ] || [ "$HTTP_CODE" = "302" ]; then
            echo "✅ 主站 HTTP 响应: $HTTP_CODE"
            HUMAN_CHECK_PASSED=$((HUMAN_CHECK_PASSED+1))
          else
            echo "❌ 主站 HTTP 响应: $HTTP_CODE（人类无法访问）"
            HUMAN_CHECK_FAILED=$((HUMAN_CHECK_FAILED+1))
          fi

          # 验证 Persona Studio 可访问
          PS_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 \
            "http://${{ env.SERVER_HOST }}/persona-studio/" 2>/dev/null || echo "000")
          if [ "$PS_CODE" = "200" ] || [ "$PS_CODE" = "301" ] || [ "$PS_CODE" = "302" ]; then
            echo "✅ Persona Studio HTTP 响应: $PS_CODE"
            HUMAN_CHECK_PASSED=$((HUMAN_CHECK_PASSED+1))
          else
            echo "⚠️ Persona Studio HTTP 响应: $PS_CODE"
            HUMAN_CHECK_FAILED=$((HUMAN_CHECK_FAILED+1))
          fi

          # 验证后端 API 健康
          API_CODE=$(ssh -i ~/.ssh/deploy_key \
            "${{ env.SERVER_USER }}@${{ env.SERVER_HOST }}" \
            "curl -s -o /dev/null -w '%{http_code}' --max-time 5 http://localhost:3002/api/ps/health 2>/dev/null || echo '000'" \
            2>/dev/null || echo "000")
          if [ "$API_CODE" = "200" ]; then
            echo "✅ Persona Studio API 健康: $API_CODE"
            HUMAN_CHECK_PASSED=$((HUMAN_CHECK_PASSED+1))
          else
            echo "⚠️ Persona Studio API 响应: $API_CODE"
            HUMAN_CHECK_FAILED=$((HUMAN_CHECK_FAILED+1))
          fi

          echo ""
          echo "━━━ 人类使用侧验证结果：${HUMAN_CHECK_PASSED} 通过 / ${HUMAN_CHECK_FAILED} 异常 ━━━"

          echo "### 👤 人类使用侧验证" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "- 通过: ${HUMAN_CHECK_PASSED}" >> $GITHUB_STEP_SUMMARY
          echo "- 异常: ${HUMAN_CHECK_FAILED}" >> $GITHUB_STEP_SUMMARY

      - name: 📝 部署汇总
        run: |
          echo "### 🚀 全站部署完成" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "- 同步范围: 全仓库（含排除规则）" >> $GITHUB_STEP_SUMMARY
          echo "- 目标: \`${{ env.SERVER_HOST }}:${{ env.SERVER_PATH }}\`" >> $GITHUB_STEP_SUMMARY
          echo "- 提交: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
          echo "- 时间: $(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M CST')" >> $GITHUB_STEP_SUMMARY
          echo "- 人类使用侧验证: 已执行" >> $GITHUB_STEP_SUMMARY

  # ═══════════════════════════════════════════════════════════════
  # Job 3: Notion 部署通知
  # ═══════════════════════════════════════════════════════════════
  notify:
    name: "📡 部署通知 → Notion"
    needs: deploy
    runs-on: ubuntu-latest
    if: success()
    steps:
      - name: 📥 检出代码
        uses: actions/checkout@v4
        with:
          fetch-depth: 2

      - name: 🟢 配置 Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: 📡 推送部署记录到 Notion
        env:
          NOTION_TOKEN:     ${{ secrets.ZY_NOTION_TOKEN }}
          CHANGES_DB_ID:    ${{ secrets.ZY_NOTION_CHANGELOG_DB }}
          EVENT_TYPE:       commit
          COMMIT_SHA:       ${{ github.sha }}
          COMMIT_MSG:       "[CD 部署] ${{ github.event.head_commit.message }}"
          COMMITTER:        ${{ github.event.head_commit.author.name || github.actor }}
          COMMIT_TIMESTAMP: ${{ github.event.head_commit.timestamp }}
          BRANCH:           ${{ github.ref_name }}
        run: |
          CHANGED=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || true)
          export CHANGED_FILES="$CHANGED"
          if [ -f "scripts/notion-bridge.js" ]; then
            node scripts/notion-bridge.js changes
            echo "✅ Notion 部署通知已发送"
          else
            echo "⏭️ scripts/notion-bridge.js 不存在，跳过 Notion 通知"
          fi

      # ━━━ 🧬 双端神经系统·自报告 ━━━
      - name: "🧬 写入神经自报告"
        if: always()
        run: |
          WORKFLOW_ID="cd-deploy"
          BRAIN="AG-SY-01"
          REPORT_DIR="data/neural-reports/cd-deploy"
          TIMESTAMP=$(TZ=Asia/Shanghai date +%Y-%m-%d-%H%M)
          STATUS="${{ job.status }}"

          mkdir -p "$REPORT_DIR"

          cat > "${REPORT_DIR}/${WORKFLOW_ID}-${TIMESTAMP}.json" << EOF
          {
            "workflow_id": "${WORKFLOW_ID}",
            "run_id": "${{ github.run_id }}",
            "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
            "status": "${STATUS}",
            "brain": "${BRAIN}",
            "event": "${{ github.event_name }}",
            "branch": "${{ github.ref_name }}",
            "commit": "${{ github.sha }}"
          }
          EOF

          git config user.name "zhuyuan-bot"
          git config user.email "zhuyuan@guanghulab.com"
          git add "$REPORT_DIR/"
          git diff --cached --quiet || \
            git commit -m "🧬 ${WORKFLOW_ID} 自报告 · ${TIMESTAMP} [skip ci]"
          git push || echo "⚠️ 自报告push失败（不阻断主流程）"
      # ━━━ 📡 指令回执·自动同步 ━━━
      - name: "📡 同步回执到 Notion"
        if: always()
        env:
          NOTION_API_KEY: ${{ secrets.ZY_NOTION_TOKEN }}
          RECEIPT_DB_ID: ${{ secrets.ZY_NOTION_RECEIPT_DB }}
        run: |
          node scripts/neural/write-receipt-to-notion.js \
            --instruction-id "${{ github.event.inputs.instruction_id || 'AUTO' }}" \
            --status "${{ job.status }}" \
            --workflow "cd-deploy" \
            --summary "cd-deploy 自动执行" \
            --related-agent "AG-SY-01"

