# Yxz Deploy Pipeline

> 游戏站部署上线流水线：GA 接入、Vercel 部署、Cloudflare DNS 配置、GSC 接入（含 HTML 文件验证 + Vercel clean-URLs 404 诊断）、SEO 基础检查、sitemap 无法抓取诊断与绕过。当需要把已搭建的游戏站正式上线、接入数据监控、绑定自定义域名、或排查 GSC sitemap / 验证文件状态时调用。

- Skill: `byte886/yxz-deploy-pipeline` (Agent Skill)
- Install (CLI): `npx skillmds@latest add byte886/yxz-deploy-pipeline`
- Raw SKILL.md: https://api.skillmd.com/api/skills/byte886/yxz-deploy-pipeline/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Marketing & Growth
- Author: byte886 (https://skillmd.com/u/byte886)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/byte886/yxz-deploy-pipeline

---


# 游戏站部署上线流水线 (Deploy Pipeline)

## 核心原则

**上线不是终点，而是开始验证搜索流量的节点。**

只有上线了，才会有收录、数据和反馈。第一个版本不用完美，先让它能被访问。

本技能覆盖从代码仓库到正式上线的完整流程：GA 接入（获取监控 ID）→ Vercel 部署 → 自定义域名绑定 → GSC 接入（搜索引擎收录）→ 上线后验证。

> **阶段顺序逻辑**：GA ID 是 Vercel 部署的环境变量，必须先获取；网站部署上线后才能绑定自定义域名；网站可访问后才能在 GSC 提交 sitemap；全部就绪后做上线后验证。

---

## 前置条件

用户需准备：
- **Gmail 账号**（用于 GSC、GA、Vercel、Cloudflare 统一注册）
- **域名**（已在 Cloudflare 管理 DNS）
- **GitHub 仓库**（已推送游戏站代码）
- **Vercel 账号**（用于部署）

### 账号与工具准备清单

| 工具 | 用途 | 注册地址 |
|------|------|----------|
| Gmail | 统一账号体系 | mail.google.com |
| Cloudflare | DNS 解析 | cloudflare.com |
| Vercel | 网站部署 | vercel.com |
| GitHub | 代码仓库 | github.com |
| Google Search Console | 搜索监控 | search.google.com/search-console |
| Google Analytics | 流量分析 | analytics.google.com |

> **重要**：建议所有平台使用同一个 Gmail 账号注册，方便 OAuth 授权自动连接。

---

## 执行流程

### 第一阶段：Google Analytics (GA) 接入

GA 帮你查看网站访问量、用户行为、停留时长等指标。本阶段获取 GA ID 并配置到项目中，为第二阶段 Vercel 部署提供环境变量。

#### 步骤 1.1：创建 GA4 媒体资源

```
# 用户手动操作：
1. 打开 https://analytics.google.com/analytics/web/
2. 点击"开始" → 设置账号名称（随意，如"我的游戏站分析"）
3. 点击"下一步" → 行业选"其他"（或最接近的行业）
4. 点击"下一步" → 勾选"我接受"服务条款
5. 平台选择"Web"
6. 输入你的完整域名
7. 点击"创建"
8. 复制 GA 衡量 ID（格式：G-XXXXXXXXXX）
```

#### 步骤 1.2：将 GA ID 配置到项目环境变量

AI 读取项目中的 `.env.local` 或 `next.config.js`，添加 GA ID 环境变量。

```
# 1. 读取项目环境配置文件
Read(file_path="{项目目录}/.env.local")
# 或
Read(file_path="{项目目录}/env.local")

# 2. 添加 GA 环境变量
Edit(file_path="{项目目录}/.env.local",
     old_string="# 已有的环境变量",
     new_string="# 已有的环境变量\nNEXT_PUBLIC_GA_ID=\"G-XXXXXXXXXX\"")
```

#### 步骤 1.3：确保 GA 代码注入页面

AI 检查项目是否已配置 GA。Next.js 推荐方式：

```
# 检查项目 layout.tsx / _app.js 是否已有 GA 脚本注入
Grep(pattern="gtag|google-analytics|NEXT_PUBLIC_GA_ID", path="{项目目录}", output_mode="files_with_matches")
```

若未注入，AI 在 `app/layout.tsx` 的 `<head>` 中添加 GA 脚本：

```tsx
// app/layout.tsx 的 <head> 中添加：
<script async src={`https://www.googletagmanager.com/gtag/js?id=${process.env.NEXT_PUBLIC_GA_ID}`} />
<script dangerouslySetInnerHTML={{
  __html: `
    window.dataLayer = window.dataLayer || [];
    function gtag(){dataLayer.push(arguments);}
    gtag('js', new Date());
    gtag('config', '${process.env.NEXT_PUBLIC_GA_ID}');
  `,
}} />
```

> ⚠️ 若项目使用 `next/script` 组件加载 GA，需使用 `strategy="afterInteractive"`。

> **GA 验证延后**：GA 是否生效需网站上线后才能验证，放在第五阶段"上线后验证"的步骤 5.1 执行。

---

### 第二阶段：Vercel 部署上线

#### 步骤 2.1：连接 GitHub 仓库

```
# 用户手动操作：
1. 打开 https://vercel.com/new
2. 点击 "Add New" → 选择 "Project"
3. 在仓库列表中找到你的游戏站仓库，点击 "Import"
   - 若仓库未显示，需先在 Vercel 授权该 GitHub 仓库
   - 建议授权 "All repositories" 方便后续新项目
4. 填写 Project Name（建议与仓库名一致）
5. Vercel 会自动识别技术栈（Next.js 会自动配置构建命令）
```

#### 步骤 2.2：配置环境变量

```
# 用户在 Vercel Import 页面操作：
1. 在 "Environment Variables" 区域添加 GA ID：
   - Key: NEXT_PUBLIC_GA_ID
   - Value: G-XXXXXXXXXX（你的 GA 衡量 ID）
   - Environment: 勾选 Production + Preview + Development
2. 点击 "Deploy"
```

> 若部署时忘记添加环境变量，可在 Vercel Project → Settings → Environment Variables 中补充，然后重新部署。

#### 步骤 2.3：等待部署完成

```
# Vercel 会自动执行：
- npm install
- next build
- 部署到 Vercel CDN

# 部署成功后：
- Vercel 会分配一个 *.vercel.app 域名（如 yourgame-wiki.vercel.app）
- 该域名可立即访问，作为临时测试站点
- 用户可先访问验证网站功能正常
```

> **常见问题处理**：
> - 构建失败：检查 Vercel 日志，常见原因是 `next.config.js` 的 `basePath` 或 `assetPrefix` 配置错误（若用了 GitHub Pages 配置，Vercel 部署需去掉这些）
> - 环境变量丢失：若之前用了 GitHub Pages 的 `next.config.mjs`，检查 `basePath` 设置

---

### 第三阶段：Cloudflare DNS 配置（绑定自定义域名）

#### 步骤 3.1：获取 Vercel DNS 记录

```
# 用户手动操作：
1. 打开 Vercel Project → Settings → Domains
2. 点击 "Add Domain" → 输入你的自定义域名（如 yourgame.wiki）→ Save
3. Vercel 会显示 2 条 DNS 记录：
   - 主域名 A 记录：指向 Vercel IP
   - www CNAME 记录：指向 Vercel CNAME
4. 分别截图或复制这两条记录的 Type / Name / Value
```

#### 步骤 3.2：在 Cloudflare 添加 DNS 记录

```
# 用户手动操作：
1. 打开 https://dash.cloudflare.com
2. 选择对应的域名
3. 左侧菜单 → DNS → Records
4. 添加 A 记录：
   - Type: A
   - Name: @（主域名）
   - Value: {Vercel 提供的 A 记录 IP}
   - Proxy status: DNS only（先关闭代理方便调试，确认正常后再开启）
5. 添加 CNAME 记录：
   - Type: CNAME
   - Name: www
   - Value: {Vercel 提供的 CNAME}
   - Proxy status: DNS only
6. 若 @ 或 www 已有其他 A/CNAME 记录，先删除或修改
7. 若有 AAAA（IPv6）记录，先删除
```

#### 步骤 3.3：等待 DNS 生效

```
# DNS 生效需要几分钟到几小时
# 生效后 Vercel Domains 页面的域名状态会变为"Valid Configuration"
# 用户可访问 https://{你的域名} 验证网站正常
```

> **⚠️ 重要**：
> - 如果 @ 或 www 已有其他 A/CNAME 记录，必须删掉或改掉，不然它们会互相冲突
> - 如果有 AAAA（IPv6）记录，先删掉——Vercel 经常会因此判定异常
> - DNS 生效后，把 Cloudflare 代理状态改为"Proxied"（橙色云朵）启用 CDN 加速

#### 步骤 3.4：检查 Vercel 域名重定向方向（关键！）

绑定自定义域名后，Vercel 默认的重定向方向常常是**反的**——默认把主域名重定向到 www，而把 www 设为 Production。这与"非 www 为主域名"的需求相反，会导致 GSC sitemap "无法抓取"。

```
# 用 playwright 检查（导航到 Vercel Domains 设置）
browser_navigate(url="https://vercel.com/{team}/{project}/settings/domains")

# 正确配置（非 www 为主域名）：
# - bigwalkguide.site      → Connect to environment → Production
# - www.bigwalkguide.site  → Redirect to Another Domain → bigwalkguide.site (308 Permanent)
# - {project}.vercel.app   → Production（Vercel 默认域名）

# ⚠️ Vercel 后台的 radio button / combobox 常被 span 元素遮挡，
# browser_click 会超时，需用 browser_evaluate 执行 JS 直接操作：
```

```js
// 切换主域名为 "Connect to environment"
document.querySelectorAll('input[type="radio"]')
  .forEach(r => r.value === 'connect-to-environment' && r.click())

// 切换 www 为 "Redirect to Another Domain"
document.querySelectorAll('input[type="radio"]')
  .forEach(r => r.value === 'redirect' && r.click())

// 设置重定向目标（在搜索框输入主域名并选下拉选项）
// 设置状态码为 308 Permanent Redirect
```

> **验证**：访问 `https://www.{域名}` 应 308 重定向到 `https://{域名}/`；访问 `https://{域名}/sitemap.xml` 地址栏**不应变化**。

#### 步骤 3.5：关闭 Cloudflare "托管 robots.txt"（关键！）

Cloudflare 的 AI Crawl Control 功能默认开启"托管 robots.txt"，会用 Cloudflare 默认内容**覆盖**项目 `public/robots.txt`，导致丢失 `Sitemap:` 指令，进而 GSC sitemap 报"无法抓取"。

```
# 关闭路径（用 playwright 导航）：
browser_navigate(url="https://dash.cloudflare.com/{account_id}/{domain}/ai/signals")

# 页面上找到"托管 robots.txt"开关，点击关闭
# 开关是 [role="switch"] 的 button 元素

# 验证：访问 https://{域名}/robots.txt
# - 修复前：内容含 "# BEGIN Cloudflare Managed content"
# - 修复后：内容为项目 public/robots.txt 的自定义内容（含 Sitemap 指令）
```

```js
// 关闭托管 robots.txt 开关
const switches = document.querySelectorAll('[role="switch"]');
for (const s of switches) {
  const container = s.closest('div');
  if (container && container.textContent.includes('托管 robots.txt')) {
    s.click();
  }
}
```

> **⚠️ 踩坑警告**：不关闭此开关，无论怎么修改 `public/robots.txt`，线上返回的都是 Cloudflare 托管内容，sitemap 中的 `Sitemap:` 指令会丢失，Google 无法发现 sitemap。

#### 步骤 3.6：域名一致性检查清单

以下 4 处必须统一为同一域名版本（都用 www 或都用非 www，推荐非 www）：

| # | 位置 | 检查方法 |
|---|------|----------|
| 1 | sitemap.xml 内的 `<loc>` URL | `Read(file_path="{项目目录}/public/sitemap.xml")` |
| 2 | robots.txt 的 `Sitemap:` 指令 | `Read(file_path="{项目目录}/public/robots.txt")` |
| 3 | layout 的 `alternates.canonical` / `openGraph.url` | `Read(file_path="{项目目录}/app/layout.jsx")` |
| 4 | GSC 资源属性 | Domain 属性（含所有子域）或 URL 前缀（需与上面 3 处一致）|

```bash
# 一致性验证（用 playwright 访问各 URL，检查地址栏不变化）
browser_navigate(url="https://{域名}/sitemap.xml")  # URL 不应变
browser_navigate(url="https://{域名}/robots.txt")   # URL 不应变
browser_navigate(url="https://www.{域名}")          # 应重定向到非 www
```

> 四者不一致时，Google 会在 www 与非 www 之间反复跳转，最终判定 sitemap "无法抓取"。

---

### 第四阶段：Google Search Console (GSC) 接入

GSC 让 Google 知道你的网站存在，帮助网站在搜索中被找到。本阶段需网站已部署上线（步骤 2.3 完成）且自定义域名已绑定（步骤 3.3 完成），因为 sitemap 提交需要网站可访问。

#### 步骤 4.1：添加资源并验证域名所有权

```
# 1. 用户需手动完成（涉及 Google 登录和 Cloudflare 授权）
⏸️ 暂停等待人工处理

请按以下步骤操作：
1. 打开 https://search.google.com/search-console
2. 点击"开始" → 输入你的域名（如 yourgame.wiki）
3. 由于域名已在 Cloudflare 管理，选择"Cloudflare"验证方式
4. 点击"授权" —— 需要 Cloudflare 处于登录状态（同 Gmail 账号最佳）
5. 授权成功后返回 GSC，确认域名已添加

完成后告诉我，我继续下一步。
```

#### 步骤 4.1.1：HTML 文件验证方式（Vercel/静态导出用户必读）

除 Cloudflare 授权外，GSC 还支持**上传 HTML 验证文件**验证所有权（更通用，适用于非 Cloudflare 管理域名的场景，也是 Google 默认推荐的验证方式之一）。但本方式在 **Vercel（尤其 `output:"export"` 静态导出）上有一个极易踩的 404 坑**。

```
# 标准流程（用户手动 + AI 配合）：
1. GSC 选择"HTML 文件"验证方式，下载 googleXXXX.html（文件名含随机串）
2. AI 把该文件放到项目 public/ 根目录：public/googleXXXX.html
   - 内容为标准一行：google-site-verification: googleXXXX.html
3. git push 触发 Vercel 重新部署
4. GSC 访问 https://{域名}/googleXXXX.html 校验内容 → 通过
```

> ⚠️ **Vercel clean-URLs 坑（关键！）**：Vercel 对静态 `.html` 文件**默认启用「干净 URL（clean URLs）」，会把 `.html` 扩展名剥掉**，文件只能以**不带扩展名**的路径访问。而 Google 校验时**必须**访问带 `.html` 的那个精确 URL，于是：
> - `https://{域名}/googleXXXX.html` → **404**
> - `https://{域名}/googleXXXX`（去扩展名）→ **200**，内容正确
> - 对照非 `.html` 静态文件（如 `favicons/favicon.ico`、`.png`/`.ico` 资源）→ **200**
>
> 这说明**文件其实已正确部署**，只是 Google 要的那个精确 `.html` URL 被 clean-URLs 改写路径导致 404。favicon 之所以正常，是因为它是 `.ico`（非 `.html`），不受该机制影响。

**诊断方法（关键，一眼区分"没部署" vs "被 clean-URLs 改写"）**：
```bash
# 三态对照，用 curl 取 HTTP 状态：
for d in 带.html路径 去.html路径 对照非.html静态文件; do curl -o /dev/null -w "%{http_code}" ...; done
# - 带.html=404 且 去.html=200 且 对照非.html=200  → Vercel clean-URLs 剥扩展名（本坑）
# - 三种都 404                                       → 文件真没部署（查 build / public / 自定义域名映射）
```

**修复（vercel.json rewrite 兜底，唯一可靠方案）**：在仓库根加 `vercel.json`，把带 `.html` 的精确 URL **rewrite** 到无扩展名路径。**只加 rewrite，不动 Vercel 已自动检测的 Next.js 导出构建配置**（避免破坏部署）：

```json
{
  "rewrites": [
    { "source": "/googleXXXX.html", "destination": "/googleXXXX" }
  ]
}
```

```bash
# 提交推送触发 Vercel 重新部署后验证（{域名} 与 {project}.vercel.app 都测）：
for d in {域名} {project}.vercel.app; do
  curl -o /dev/null -w "%{http_code}" https://$d/googleXXXX.html   # 应 200
done
# 内容应为：google-site-verification: googleXXXX.html
```

> **⚠️ 踩坑警告**：
> - 别去折腾"构建缓存"或"postbuild 拷贝 public/→out/"——文件本来就在 `out/` 里，是 Vercel 的路径改写导致 404，那两个方向都治标不治本。
> - rewrite 只匹配未命中的路径，不影响页面路由；`destination` 用无扩展名路径即可（Vercel 会返回该静态文件内容，URL 栏仍显示 `.html`，Google 校验通过）。
> - **通用规律**：任何 Vercel 静态导出站上放「根目录 `.html` 验证文件」（Google / Bing / 百度站长验证）都会踩同一坑，统一用 `vercel.json` rewrite 兜底。
> - 若不想用 rewrite，也可改用 **DNS TXT 记录验证**（在域名 DNS 加一条 TXT），彻底绕开静态文件服务问题。

#### 步骤 4.2：请求首次索引

```
# 用户手动操作：
1. 在 GSC 后台顶部搜索框输入完整域名，按回车
2. 若显示"URL 已被索引"也需重新提交
3. 点击右上角"测试"按钮
4. 测试成功后点击"请求索引"
5. 等待索引请求成功提示
```

#### 步骤 4.3：提交 Sitemap

```
# 用户手动操作：
1. GSC 左侧菜单点击"站点地图"
2. 在"添加新的站点地图"输入框输入完整 URL：https://{你的域名}/sitemap.xml
3. 点击"提交"
4. 出现"已成功提交站点地图"对话框即为成功
5. 打开该 URL 确认 sitemap 已就绪
```

> **⚠️ 踩坑警告**：输入框必须填**完整 URL**（`https://{域名}/sitemap.xml`），不能只填相对路径（`sitemap.xml`）。GSC 会判定相对路径"站点地图地址无效"，必须带协议和域名。

> **验证通过标准**：GSC 后台能看到域名属性，sitemap 已提交，索引请求成功。

#### 步骤 4.4：sitemap 状态卡死的绕过方案（提交 atom.xml）

若 sitemap.xml 修复后 GSC 状态长期显示"无法抓取"（超过 24-48 小时），可参考曲线救国方案：**生成并提交 atom.xml 作为替代 sitemap 资源**。GSC 支持 RSS/Atom feed 作为 sitemap，提交一个新的 sitemap 资源可绕过卡死的状态字段。

参考：`https://blog.rimuru.work/2026/03/26/解决Google-Search-Console无法抓取站点地图sitemap-xml/`

实现方式（以 `scripts/gen-seo.mjs` 为例）：

```js
// 1. 在 gen-seo.mjs 中新增 Atom 1.0 feed 生成
//    - 每个 <entry> 对应一个页面 URL
//    - <title>/<summary> 取自 site.config.json 的 pages 配置
//    - XML 特殊字符必须转义（& → &amp;）
// 2. 更新 robots.txt 同时声明两个 sitemap：
//    Sitemap: https://{域名}/sitemap.xml
//    Sitemap: https://{域名}/atom.xml
// 3. 在 .gitignore 中添加 public/atom.xml（自动生成不入库）
// 4. git push 触发 Vercel 部署
// 5. 验证 https://{域名}/atom.xml 返回 application/atom+xml
// 6. 在 GSC 提交完整 URL：https://{域名}/atom.xml
```

> **验证 atom.xml 在线**：`browser_evaluate` 检查 `document.contentType === 'application/atom+xml'` 且 entry 数量正确。

> **适用场景**：仅当 sitemap.xml 实际可访问（URL 检查工具验证通过）但 GSC 列表状态长期不更新时使用。不能替代对根本原因（重定向/robots.txt/域名一致性）的修复。

#### 步骤 4.5：删除错误的 sitemap 记录

若 GSC 列表中存在重复或错误的 sitemap 记录（如 www 版本、带尾斜杠版本），需逐条删除：

```
# ⚠️ 列表页行尾的"三个点"按钮没有"移除站点地图"选项！
# 必须进入详情页才能删除：

1. 点击对应的 sitemap URL（如 https://www.{域名}/sitemap.xml）
   → 进入详情页（URL 变为 /sitemaps/info-drilldown?...）
2. 点击页面右上角"更多选项…"（三个点按钮）
3. 在展开的菜单中点击"移除站点地图"
4. 在"要移除站点地图吗？"对话框中点击"移除"
5. 页面返回列表，底部提示"站点地图已移除"
```

> **Playwright 操作技巧**：GSC 菜单项的 `jsaction` 需要触发完整事件序列（mousedown/mouseup/click），单纯 `element.click()` 可能无效。用 `browser_evaluate` 分发 MouseEvent 更可靠：

```js
() => {
  const items = document.querySelectorAll('[role="menuitem"]');
  for (const item of items) {
    if (item.textContent.includes('移除站点地图')) {
      ['mousedown','mouseup','click'].forEach(type => {
        item.dispatchEvent(new MouseEvent(type, {bubbles:true, cancelable:true, view:window}));
      });
      return 'dispatched';
    }
  }
}
```

---

### 第五阶段：上线后验证与 SEO 基础检查

网站已部署上线、自定义域名已绑定、GSC 已接入，现在进行上线后第一轮全面验证。

#### 步骤 5.1：验证 GA 是否已生效

```
# 用户手动验证：
1. 网站上线后，打开 GA 后台
2. 右上角点击"管理" → 中间列点击"数据流"
3. 找到你的数据流，点击"查看数据流"
4. 右下角"报告"标签 → 右上角"实时"
5. 打开你的网站，几秒后 GA 应检测到访问
6. 若显示绿色"已检测"则成功；若黄色感叹号需等待几分钟更新
```

#### 步骤 5.2：检查三项技术配置

AI 检查项目代码中是否包含以下 SEO 基础设置：

```
# 1. 检查 canonical URL 设置
Grep(pattern="canonical|rel=.canonical", path="{项目目录}", output_mode="content")
# 确保页面 head 中有 <link rel="canonical" href="https://{你的域名}/" />

# 2. 检查 301 重定向配置
# Vercel 用户可在 vercel.json 或 next.config.js 中配置：
Grep(pattern="redirects|301|www", path="{项目目录}", output_mode="content")
# 确保 www 版本指向非 www 版本（或反过来），统一只用一个

# 3. 检查 HTTPS
# Cloudflare 自动配置，用户验证：
# - 浏览器访问 https://{你的域名} 地址栏有锁图标
# - 不需要代码层额外配置
```

#### 步骤 5.3：检查 robots.txt 和 sitemap.xml

```
# 1. 检查 robots.txt 源文件内容
Read(file_path="{项目目录}/public/robots.txt")
# 确保包含正确的域名，无旧站残留，必须含 Sitemap 指令：
#   User-agent: *
#   Allow: /
#   Sitemap: https://{你的域名}/sitemap.xml

# 2. 检查线上 robots.txt 是否被 Cloudflare 托管覆盖（关键！）
browser_navigate(url="https://{你的域名}/robots.txt")
browser_evaluate(function="() => document.body.innerText")
# 若内容含 "# BEGIN Cloudflare Managed content" → 回到步骤 3.5 关闭托管开关
# 若内容为自定义内容（含 Sitemap 指令）→ 正常

# 3. 检查 sitemap.xml 是否可访问且无重定向
browser_navigate(url="https://{你的域名}/sitemap.xml")
# 验证：地址栏 URL 不变（未重定向到 www），contentType 为 application/xml
# 若 URL 变成 www 版本 → 回到步骤 3.4 修正 Vercel 域名重定向方向
```

> **⚠️ 关键**：线上 robots.txt 可能被 Cloudflare 托管内容覆盖，必须检查**线上实际返回**而非仅检查源文件。sitemap.xml 访问时若有重定向，Google 会判定"无法抓取"。

#### 步骤 5.4：检查 meta 标签完整性

```
# AI 检查所有页面的 SEO meta 标签
# 1. 首页和内页都应有：
#    - <title> 含关键词，40-60 字符
#    - <meta name="description"> 含关键词，140-160 字符
#    - <meta name="keywords"> 含关键词，≤100 字符
#    - <link rel="canonical"> 指向正确 URL

# 2. 全项目搜索检查
Grep(pattern="old-game-name|旧站域名|占位符", path="{项目目录}", output_mode="content")
```

#### 步骤 5.5：检查页面可访问性

```
# AI 用浏览器验证所有页面可正常访问
run_mcp("mcp_playwright-extension", "browser_navigate",
        args={"url": "https://{你的域名}"})
run_mcp("mcp_playwright-extension", "browser_wait_for", args={"time": 3})
run_mcp("mcp_playwright-extension", "browser_take_screenshot",
        args={"type": "png", "scale": "css", "fullPage": false})

# 检查要点：
# - 首页正常加载，无 404 或白屏
# - 导航链接可点击跳转
# - 页面内容完整（标题、正文、侧边栏）
# - 主题色和样式正确
```

---

### 第六阶段：复用模板防残留检查（关键！）

若用户从现有游戏站模板复制代码创建新站，AI 必须执行以下检查：

#### 步骤 6.1：全站旧内容扫描

```
# 1. 扫描旧游戏名残留
Grep(pattern="{旧游戏名}|{旧站域名}|{对标站名称}",
     path="{新站项目目录}", output_mode="content", -i=true)

# 2. 扫描旧站 URL
Grep(pattern="{旧站完整URL}",
     path="{新站项目目录}", output_mode="content")

# 3. 扫描 robots.txt / sitemap.xml / SEO 配置
Read(file_path="{新站项目目录}/public/robots.txt")
Grep(pattern="sitemap|Sitemap", path="{新站项目目录}", output_mode="content")

# 4. 扫描所有配置文件
Glob(path="{新站项目目录}", pattern="**/*.{json,js,ts,md}")
```

#### 步骤 6.2：修正残留内容

AI 将所有旧游戏名、旧域名、旧 URL 替换为新站对应内容。

```
# 全站替换旧游戏名 → 新游戏名
# 全站替换旧域名 → 新域名
# 更新 robots.txt 中的 sitemap 路径
# 更新 sitemap.xml 中的所有 URL
# 更新 SEO 配置中的 title/description/keywords
# 更新 footer 中的官方链接
```

#### 步骤 6.3：验证修复

```
# 再次 Grep 扫描，确保零残留
Grep(pattern="{旧游戏名}|{旧站域名}", path="{新站项目目录}", output_mode="count")
# 结果应为 0 条

# 构建后再次验证
RunCommand(command="npm run build", cwd="{新站项目目录}",
           blocking=true, requires_approval=false)
# 检查产物 out/ 中无旧内容残留
```

> **⚠️ 踩坑警告**：复用模板上线新站时，残留旧站 URL 会导致 Google 判定重复/抄袭内容，严重影响收录和排名。

---

## 执行要点

1. **GA ID 必须先于 Vercel 部署获取**：GA ID 是 Vercel 部署的环境变量，第一阶段获取 ID 后才能在第二阶段部署时配置
2. **GSC 接入必须在网站上线后**：sitemap 提交需要网站已可访问，需第二阶段部署 + 第三阶段域名绑定完成后再接入 GSC
3. **GA ID 用环境变量**：不要硬编码在代码里，用 `NEXT_PUBLIC_GA_ID` 环境变量
4. **Vercel 部署前确认环境变量**：部署时忘记加，后面补了还要重新部署
5. **Cloudflare DNS 冲突清理**：A/CNAME 记录不能与旧记录共存，必须删掉或改掉
6. **AAAA 记录必须删除**：Vercel 不支持 IPv6，残留 AAAA 会导致验证失败
7. **canonical URL 必须设置**：告诉 Google 哪个 URL 是正式版本
8. **301/308 重定向必须配置**：www 和非 www 版本必须统一，分散权重
9. **Vercel 域名重定向方向必须检查**：Vercel 默认方向常是反的（主域名→www），必须改为 www→主域名
10. **Cloudflare 托管 robots.txt 必须关闭**：否则会覆盖项目 robots.txt，丢失 Sitemap 指令
11. **域名四点一致性**：sitemap URL、robots Sitemap 指令、canonical、GSC 资源必须统一 www/非 www
12. **Sitemap 必须先提交**：提交后 Google 才会开始爬取你的网站
13. **GA 验证需上线后执行**：GA 实时数据检测在第五阶段步骤 5.1，需网站已上线
14. **实时数据验证**：GA 需要等几分钟才能检测到访问，不要急着下结论
15. **索引时间预期**：新站首次索引 1-7 天（甚至 1-2 周）；sitemap 状态更新几小时到 24 小时；"请求编入索引"几小时到 24 小时。GSC 显示的状态是历史快照，修复后需等 Google 重新抓取才更新
16. **持续更新计划**：建立每周/月更新计划，持续添加新游戏或丰富热门页面内容
17. **GSC 提交 sitemap 必须用完整 URL**：相对路径会被判定"地址无效"，必须带协议和域名（`https://{域名}/sitemap.xml`）
18. **GSC 列表状态 ≠ 实际可抓取性**：列表"状态"列有 24-48h 缓存延迟，URL 检查工具才是实时验证。修复后用 URL 检查工具确认，而非盯着列表状态
19. **sitemap 状态卡死的绕过方案**：提交 atom.xml（Atom feed）作为新 sitemap 资源，GSC 支持 RSS/Atom feed 作为 sitemap（步骤 4.4）
20. **删除错误 sitemap 记录必须进详情页**：列表页行尾三个点菜单没有"移除站点地图"选项，必须点击 URL 进入详情页，在"更多选项"中才有（步骤 4.5）
21. **Playwright 操作 GSC 菜单项**：GSC 的 jsaction 需要完整事件序列（mousedown/mouseup/click），`browser_click` 可能超时，用 `browser_evaluate` 分发 MouseEvent 更可靠；输入框用 `slowly: true` 逐字输入触发 key handler 启用提交按钮
22. **GSC HTML 验证文件在 Vercel 上 404 = clean-URLs 剥扩展名**：Vercel 默认对静态 `.html` 文件启用 clean URLs，文件只能以无扩展名路径访问，而 Google 要求的精确 `.html` URL 会 404。诊断用「带扩展名(404)/去扩展名(200)/对照非 .html 静态文件(200)」三态对比，一眼区分"没部署"vs"被改写路径"；修复用仓库根 `vercel.json` rewrite 兜底（步骤 4.1.1），别去折腾构建缓存或 postbuild 拷贝——文件本就在 `out/` 里，是路径改写导致 404

---

## 常见问题排查

| 问题 | 原因 | 解决方案 |
|------|------|----------|
| GSC 验证失败 | Cloudflare 未登录 | 登录 Cloudflare（同 Gmail），重新授权 |
| GA 显示黄色感叹号 | GA 代码未生效 | 等 3-5 分钟，检查环境变量和脚本注入 |
| Vercel 构建失败 | 环境变量缺失/配置错误 | 检查 next.config.js，补充环境变量后重建 |
| 域名无法访问 | DNS 记录冲突 | 清理 A/AAAA/CNAME 冲突记录，等待 DNS 生效 |
| GSC 索引为 0 | 未提交索引或 sitemap | 在 GSC 手动请求索引，提交 sitemap |
| 网页加载慢 | Cloudflare 代理未开启 | 开启 Cloudflare 橙色云朵代理状态 |
| Google 不收录 | 内容与旧站重复 | 彻底清理旧站残留，提交 sitemap |
| **GSC sitemap "无法抓取"** | 三大原因之一（见下方诊断流程） | 按下方"sitemap 无法抓取诊断流程"排查 |
| **GSC sitemap 状态不更新** | Google 用的是修复前缓存 | 等几小时到 24 小时，Google 重新抓取后自动更新 |
| **GSC sitemap 状态长期不更新** | 状态字段卡死，修复后仍显示"无法抓取" | 用 URL 检查工具实时验证；若仍不更新则提交 atom.xml 绕过（步骤 4.4） |
| **GSC 提交 sitemap 报"地址无效"** | 输入了相对路径（如 `sitemap.xml`） | 必须输入完整 URL：`https://{域名}/sitemap.xml` |
| **GSC 列表有重复/错误 sitemap 记录** | 历史提交了 www/带斜杠等版本 | 进入详情页→更多选项→移除站点地图（步骤 4.5） |
| **GSC HTML 验证文件 404（文件已部署但精确 .html URL 404）** | Vercel clean-URLs 默认剥掉静态 `.html` 扩展名，文件只能在无扩展名路径访问 | 诊断：对比 带.html(404)/去.html(200)/对照非.html静态文件(200) 三态；修复：仓库根加 vercel.json，rewrite `/googleXXXX.html` → `/googleXXXX` 后重部署（步骤 4.1.1） |

### sitemap "无法抓取" 诊断流程

按顺序排查以下三大常见原因：

**① sitemap URL 被重定向（最常见）**
```
# 用 playwright 访问 sitemap，检查地址栏是否变化
browser_navigate(url="https://{域名}/sitemap.xml")
# 若 URL 变成 www 版本 → Vercel 域名重定向方向反了
# 修复：步骤 3.4，把主域名设为 Production，www 设为重定向到主域名
```

**② robots.txt 被 Cloudflare 托管覆盖**
```
# 用 playwright 访问线上 robots.txt
browser_navigate(url="https://{域名}/robots.txt")
browser_evaluate(function="() => document.body.innerText")
# 若内容含 "# BEGIN Cloudflare Managed content" → Cloudflare 托管未关闭
# 修复：步骤 3.5，关闭 Cloudflare → AI Crawl Control → 信号 → 托管 robots.txt
```

**③ 域名四点不一致**
```
# 检查以下 4 处 www/非 www 是否统一：
# 1. sitemap.xml 内 <loc> URL
# 2. robots.txt 的 Sitemap 指令
# 3. layout 的 alternates.canonical
# 4. GSC 资源属性
# 修复：步骤 3.6，统一为同一域名版本
```

**最终验证（模拟 Googlebot）**：
```js
// 用 browser_evaluate 模拟 Googlebot 访问，确认技术上可抓取
const res = await fetch('https://{域名}/sitemap.xml', {
  redirect: 'follow',
  headers: {'User-Agent': 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'}
});
// 预期：status=200, redirected=false, contentType=application/xml
```

**GSC URL 检查工具（实时验证，权威）**：
```
# GSC 列表"状态"列是历史快照（修复前的抓取结果），有 24-48h 缓存延迟
# URL 检查工具是实时模拟 Googlebot 抓取，结果更准确、即时

1. GSC 顶部搜索框输入 sitemap URL：https://{域名}/sitemap.xml
2. 回车进入 URL 检查页面
3. 查看右侧"网址检查"结果：
   - "网址可以在 Google 上访问" → 技术上可抓取，列表状态是缓存延迟
   - "网址无法访问" / 重定向错误 → 需回到上方诊断流程排查
4. 若显示可访问，点击"测试实际网址"→"请求编入索引"加速收录
```

> **判断逻辑**：URL 检查工具显示可访问 + 上述模拟 Googlebot fetch 返回 200 → 技术上已修复，GSC 列表"无法抓取"是缓存延迟，等待 Google 重新抓取（通常 24-48 小时）即可自动更新。

> **若 24-48 小时后列表状态仍不更新**：转步骤 4.4，生成并提交 atom.xml 作为替代 sitemap 资源绕过卡死状态。

---

## 输出文件

执行完成后产出：

1. **GA 接入确认**：GA ID 已获取并配置到项目环境变量，GA 脚本已注入页面
2. **Vercel 部署成功**：网站可通过 Vercel 分配的域名和自定义域名访问
3. **Cloudflare DNS 配置完成**：自定义域名已绑定到 Vercel，重定向方向正确
4. **GSC 接入确认**：域名已在 GSC 验证通过，sitemap 已提交，索引请求成功
5. **上线后验证通过**：GA 实时数据检测通过，SEO 配置（canonical、301、HTTPS）确认
6. **残留内容检查**（若适用）：旧站内容已全部替换，零残留

### 部署检查清单（用户确认用）

```markdown
# 上线部署检查清单

## GA 接入
- [ ] GA 衡量 ID 已获取
- [ ] 环境变量 NEXT_PUBLIC_GA_ID 已配置
- [ ] GA 脚本已注入页面

## Vercel 部署
- [ ] GitHub 仓库已连接
- [ ] 环境变量已配置（含 GA ID）
- [ ] 构建部署成功
- [ ] Vercel 临时域名可访问

## 自定义域名
- [ ] A 记录已添加到 Cloudflare
- [ ] CNAME 记录已添加到 Cloudflare
- [ ] DNS 生效，自定义域名可访问
- [ ] Cloudflare 代理已开启（橙色云朵）
- [ ] Vercel 域名重定向方向正确（www → 主域名，非 www 为 Production）
- [ ] Cloudflare 托管 robots.txt 已关闭
- [ ] 域名四点一致性（sitemap/robots/canonical/GSC）已检查

## GSC 接入
- [ ] 域名已在 GSC 添加并验证
- [ ] 验证方式：Cloudflare 授权 或 HTML 文件（若用 HTML 文件，Vercel 站需 vercel.json rewrite 使 googleXXXX.html 返回 200，见步骤 4.1.1）
- [ ] sitemap.xml 已提交（用完整 URL，非相对路径）
- [ ] 已请求首次索引
- [ ] GSC 列表无重复/错误 sitemap 记录（www/带斜杠版本已删除）
- [ ] 若 sitemap 状态长期"无法抓取"：URL 检查工具验证可访问 + 必要时提交 atom.xml 绕过

## 上线后验证
- [ ] GA 实时数据检测通过（绿色）
- [ ] canonical URL 已设置
- [ ] www → 非 www 重定向已配置
- [ ] HTTPS 正常（浏览器有锁图标）
- [ ] robots.txt 正确（线上实际内容，非 Cloudflare 托管）
- [ ] sitemap.xml 可访问且无重定向（地址栏不变）

## 无残留检查
- [ ] 旧游戏名零残留
- [ ] 旧域名零残留
- [ ] 占位符零残留
```

---

## 后续维护建议

1. **每周数据查看**：GSC 查看搜索排名、点击量；GA 查看访问量、跳出率
2. **页面优化**：根据数据表现，优化高跳出率页面，丰富高点击率页面内容
3. **持续更新**：建立周/月更新计划，添加新游戏或延伸热门页面内容
4. **定期爬取**：在 GSC 定期请求重新索引更新的页面
5. **扩展 GA 功能**：配置目标追踪、事件追踪等高级分析功能

