WeddingAI.video · Architecture Overview

在 Cloudflare Pages 上 静态优先
搭一个多语言 AI 婚礼视频站

功能上服务三类客户(新人、家庭、远距亲友),技术上把 80+ HTML 页面推到 CDN 边缘,在 Workers 里加 8 步中间件管线做 i18n 注入、CSP nonce 生成与 SEO 头规范化,再把表单与死信队列写到 KV。下面两张图先讲清楚用户能看到什么,再讲清楚代码是怎么组织的。

10
i18n 语言 (en/zh/es/fr/de/pt/ja/ru/ar/th)
~80
静态 HTML 模板 (首页 + 服务 + 博客)
50+ 篇
SEO 博客 (articles/*.md → /blog/)
5
Workers 函数 (middleware + 4 API)
1 KV
LEAD_STORAGE: 限流 + DLQ 复用
01 · 功能架构

访客能看到 五大模块

从访客视角看,这个站分五块:三组服务(个性化、视频增强、离别补偿)是核心转化点;博客 + 资源中心是 SEO 引流的主入口;定价 + 订购 + 成功页是收口;信任与合规层散落全站。下方是按转化路径梳理的页面树。

入口层 · ENTRY 首页 / Hero + 卖点 + 案例 博客 /blog/ 50+ SEO 文章 资源中心 /resources/ 画廊 /gallery/ 案例视频 价格 /pricing/ 3 档套餐 联系 /about/ quote API 入口 搜索 /search/ 全文检索 服务层 · CORE SERVICES (3 大类 / 9 个 SKU) PERSONALIZATION 个性化创作 · 6 SKU AI Video Generator /services/personalization/ai-video-generator/ Pet Wedding /services/personalization/pet-wedding/ Wedding Trailer /services/personalization/wedding-trailer/ Multilingual /services/personalization/multilingual/ Cartoon Style /services/personalization/cartoon-style/ VIDEO ENHANCEMENT 视频后期 · 1 SKU Slow Motion /services/video-enhancement/slow-motion/ 更多增强类 SKU 待拓展(色彩、降噪、) 由 _redirects 的 short URL 映射到目录 短链: /slow-motion/ → /services/video-enhancement/slow-motion/ ABSENCE COMPENSATION 离别补偿 · 3 SKU Family Message /family-message/ Family Tribute /family-tribute/ Celebrity Msg /celebrity-message/ 用 _redirects 把短链 308 到完整路径 便于社媒分享 + 旧外链回链 转化层 · CONVERSION 订购 /order/ 3 步表单 套餐 → 资料 → 确认 成功 /success/ noindex, 订单回执 邮件由 Resend 发送 报价 API /api/quote (POST) 限流 5/分/IP, 写 KV 死信 DLQ /admin/leads/ 管理员重发失败邮件 信任与合规 /about/ · /privacy/ · /terms/ /404 · /offline · /sitemap*.xml 横切关注点 · CROSS-CUTTING I18N · 10 种语言 每种语言一份 i18n/xx.json + js/i18n.js 客户端切换 + _middleware.js 边缘注入 en zh es fr de pt ja ru ar* th * ar 是 RTL, 中间件自动加 dir="rtl" 📂 i18n/{en,zh,es,fr,de,pt,ja,ru,ar,th}.json 📂 js/i18n.js · js/langs.js · js/cookie-consent.js 🔁 _redirects 把 /xx/* → /* (200 内部重写) 🏷 hreflang + canonical + og:locale 在每页静态写入 SEO & AI 索引 让 Google、Bing 和 LLM 都能完整读到这个站 📄 sitemap.xml + sitemap-{lang}.xml × 10 🤖 llms.txt + llms-full.txt (自动生成, scripts/gen_llms.py) 📋 Schema.org JSON-LD (每页手写, qa/dedup_noscript.py 去重) 📡 IndexNow — 改完即推, /indexnow-key.txt 是验证 key 🔗 manifest.json PWA, sw.js 离线缓存 📊 旧 numeric blog 路径 301 → 新 semantic slug (50 条) 🎯 LCP hero + preload + AVIF/WebP 多断点
02 · 代码架构

技术上分 六层 + 一条工具链

所有静态 HTML/CSS/JS/图片推到 Cloudflare CDN 边缘,五个 Workers 函数跑中间件和 API,KV 承担限流和死信队列。构建/部署工具全在根目录 Python 脚本和 internal-tools/ PowerShell 里,不进 deploy 包。

L1

客户端静态层 · Static Client

浏览器直接拿,无 JS 也能看
index.html about/ blog/<50 篇>/ services/<9 个>/ order/ pricing/ 404.html offline.html styles.css styles.min.css js/main.min.js js/i18n.js js/langs.js js/cookie-consent.js images/<多断点> AVIF · WebP · PNG manifest.json sw.js
L2

边缘计算层 · Cloudflare Workers (functions/)

每个请求都在边缘走 8 步管线
_middleware.js ① Accept-Language 首次自动重定向 + cookie ② /xx/* 200 内部 rewrite ③ 加载 i18n/xx.json 服务端注入 data-i18n ④ <html lang> + canonical + hreflang 重写 ⑤ og:locale + JSON-LD inLanguage 改写 ⑥ /success/ 注入 noindex ⑦ per-request CSP nonce 替换 gJeR5w0BWoD4l1+HaZBkBg== ⑧ 设置 CSP / HSTS / COOP 响应头 api/quote.js POST 报价 + 限流 + Resend api/dead-letters.js DLQ viewer (token 鉴权) __csp_report.js 违规上报端点 docs/[id].js 文档元数据 _lib/langs.js LANGS / DEFAULT_LANG / RTL 表
L3

数据层 · Storage Bindings

单 KV 命名空间,前缀复用
LEAD_STORAGE (KV) rl:<ip> 限流计数 5/min/IP dl:<id> 死信队列 Resend 失败回退 RATE_LIMIT_KV (alias) 向后兼容 images/ → R2 (未来) D1 — 暂未使用
L4

第三方集成 · Third-Party

CSP 白名单 + preconnect
GA4 (gtag.js) Cloudflare Web Analytics (beacon) Google AdSense (lazy 注入) Resend (事务邮件) IndexNow (URL 推送 API) Bing Webmaster (sitemaps)
L5

路由 & 安全配置层 · Edge Config

Workers 启动前由 Cloudflare Pages 加载
wrangler.toml name · compatibility_date · KV 绑定 _redirects 11 类规则: .html→/, 短链→目录, 旧 blog 301, i18n 200, 内部文件 404! _headers HSTS 2y · X-Frame · Permissions-Policy · COOP · Referrer-Policy · preconnect · 缓存粒度
L6

构建 & 运维工具链 · Tooling

根目录 Python 脚本 + internal-tools/ PowerShell + scripts/
图片 pipeline generate-responsive.py generate-avif.py optimize-images.py recompress-png.py HTML 注入 inject-srcset.py inject-avif-source.py inject-dimensions.py inject-critical-css.py HTML 修复 flatten-avatar-wrapper.py unwrap-picture.py fix-*-paths.py × 4 内容生成 generate-blog.py generate-llms-full.py 内部 PowerShell (.assetsignore 排除) internal-tools/pre-deploy-check.ps1 internal-tools/update-sitemap.ps1 internal-tools/deploy.ps1 internal-tools/normalize-head-styles.ps1 + 18 个其它 .ps1

根 .py + scripts/*.py 走 .assetsignore 排除,不进 deploy 包。internal-tools/ 同上(额外 _redirects 兜底 404!)

03 · 请求生命周期

一个 /zh/services/personalization/pet-wedding/ 请求的 8 步

挑了一个最常见的路径:中文用户访问宠物婚礼服务页。走完这条管线,浏览器拿到的 HTML 已经是完全中文化的、nonce 已注入、CSP 头已下发、hreflang 全套齐全的最终态。

  1. STEP 01 · EDGE RECEIVE

    Cloudflare 边缘节点接收请求

    DNS 解析到最近的 PoP,命中 Cache-Control: max-age=60(HTML) 或直接 miss。CDN 缓存未命中,把请求转给同节点的 Workers runtime。

  2. STEP 02 · _MIDDLEWARE.JS LANG DETECT

    中间件识别 /zh/ 前缀,加载 zh 语言包

    从 URL 路径第一段 /zh/ 拿到目标语言 zh,跳过 Accept-Language 自动重定向(已经在 /zh/ 下)。检查 wa_lang_user cookie 确认是否用户主动切过。

  3. STEP 03 · STATIC FILE FETCH

    从静态资源拉 /services/personalization/pet-wedding/index.html

    中间件内部 fetch 同源 URL(去掉 /zh/ 前缀),拿到英文 HTML 模板。KV 零交互——这一步纯粹是边缘缓存里的静态文件。

  4. STEP 04 · I18N INJECTION

    加载 i18n/zh.json,把 data-i18n key 替换为译文

    正则扫描所有 data-i18n="architecture.key_placeholder.00000001" 元素,用 zh.json 里的值覆盖 innerText。Googlebot 在这一步就拿到完整中文 HTML,不是英文源 + 客户端 JS 翻。

  5. STEP 05 · HEAD NORMALIZATION

    改 <html lang="zh">、canonical、hreflang、og:locale、JSON-LD

    五个 head 元素逐个重写。canonical 指向 /zh/services/.../,hreflang 列出全部 10 种语言,og:locale 改 zh_CN,JSON-LD 的 inLanguage 改 zh。这一步让每种语言都拥有独立可索引的 URL。

  6. STEP 06 · CSP NONCE GEN

    用 crypto.getRandomValues 生成 16 字节 nonce

    每个请求独立 nonce,base64 编码后 22 字符。把 HTML 里所有 gJeR5w0BWoD4l1+HaZBkBg== 占位符 + 所有 <script> 标签(没 nonce 的)都注入这个 nonce。

  7. STEP 07 · CSP HEADER SET

    把 nonce 写入 Content-Security-Policy 响应头

    script-src 加 'nonce-XXX' 'strict-dynamic',允许 GA4/AdSense/Cloudflare Insights 加载。HTML 里的 nonce 和 CSP 头里的 nonce 必须严格一致——记忆里 2026-07-29 的故障就源于保存了 post-middleware HTML 导致硬编码。

  8. STEP 08 · BROWSER RENDER

    200 OK, 浏览器解析 + 预连接 + 加载 nonce'd JS

    preconnect 已经在 _headers 里 Link: 预热 GA/AdSense/Insights。main.min.js、i18n.js、langs.js 因为带了合法 nonce,被 strict-dynamic 放行。语言切换器、cookie consent banner、GA4 事件全部正常加载——一切就位。

04 · 关键模块速查

找东西 来这里翻

如果你要改某个功能,先看它落在哪个组、对应哪些文件、有什么坑。memory 里那些反复踩的坑都收在"已踩过的坑"里。

路由 & 国际化
URL 重写
_redirects — 11 类规则;.html 308→目录 / 短链 308→完整路径 / /xx/* 200 内部 rewrite / 旧 blog 301 / 内部文件 404!
语言切换
_middleware.js 边缘注入 + js/i18n.js 客户端切换器 + js/langs.js 语言元数据 + i18n/{lang}.json 翻译源
hreflang / canonical
静态写入每页 head;中间件按访问语言重写 canonical + og:locale + JSON-LD inLanguage
性能 & 资源
图片 pipeline
源图 → generate-responsive.py(WebP/PNG 多断点)→ generate-avif.py(AVIF)→ inject-srcset.py + inject-avif-source.py(写 HTML)→ 手动 fix Windows 反斜杠
缓存策略
HTML 60s / blog 300s / sitemap 1h / llms.txt 24h / 图片字体 1y;CSS/JS 用 ?v=N 版本号破缓存
LCP 优化
preload LCP hero, AVIF 优先(浏览器自动协商), fonts subset, 关键 CSS 注入, sw.js 离线
安全
CSP strict-dynamic + nonce
中间件每请求生成 nonce, 替换 gJeR5w0BWoD4l1+HaZBkBg== + 给 <script> 自动加 nonce。记住:HTML 源里只能放占位符,不能放真 nonce
Headers 全家桶
HSTS 2y · X-Frame SAMEORIGIN · Permissions-Policy 禁用相机/麦克风/支付等 · COOP same-origin · Referrer-Policy strict-origin-when-cross-origin
内部文件防泄漏
.assetsignore 排除 + _redirects `404!` 强兜底,应对 wrangler 4.114 目录排除的 bug
可观测 & 运维
分析
GA4 gtag (lazy 注入) + Cloudflare Web Analytics (beacon, 无 cookie) + AdSense (lazy)
死信与重发
Resend 失败 → /api/dead-letters 写 KV dl:<id> → /admin/leads/ 用 DLQ_TOKEN 看 + 重发
CSP 违规上报
__csp_report.js 收 report-uri 端点 + report-to 头,事后扫日志找被 strict-dynamic 误杀的脚本
已踩过的坑 (来自项目 memory)
硬编码 CSP nonce
曾经保存过 post-middleware HTML 回来,导致 HTML 里的 nonce 不等于响应头 nonce,所有 JS 被 strict-dynamic 静默屏蔽。修复:占位符统一为 gJeR5w0BWoD4l1+HaZBkBg==
Windows 反斜杠
Python 用 str(Path(...)) 拼 URL → \images/foo.avif,浏览器不转,全 404。修复:str 后 replace("\\","/") 或用 PosixPath 起点
嵌套 <picture> + 相对路径 srcset
flatten-avatar-wrapper.py 没拆干净 + Windows 反斜杠 + dedupe 正则错配,三连击。特征:浏览器收 nested picture 内的相对 srcset 解析为 /foo.avif(不是 /images/foo.avif)
Cloudflare Pages dir/index 308 自环
zone-level URL Normalization 开关会覆盖 _redirects 200 规则,导致 /foo 308 → /foo 自环。修复:关掉 zone 那个开关,改靠 _redirects 处理
never-upscale 漏配
srcset 引用了 1280w 但 generate-responsive.py 因为源图只 1280w 跳过了该变体。修复:扩源图到 ≥1920w,手动补 1600/1920w 变体
05 · 业务数据流

从用户素材到 AI 成品 的全链路

这站本身不"存储"婚礼视频——用户上传的素材由人工/AI 在线下游处理,成品通过邮件 + CDN 回流。这里画的是数据形态在每个节点的变化,以及哪些字节会落进哪些存储。

4 个阶段 · 6 种数据形态 ① INPUT ② EDGE ③ STORE ④ DELIVER 用户素材 照片 / 视频 / 文字需求 浏览器行为 点击 / 滚动 / 语言切换 表单提交 姓名 / 邮箱 / 套餐 / 留言 CSP 违规 被拦截的 inline / 外链脚本 搜索爬虫 Googlebot / Bingbot / GPTBot _middleware.js i18n 注入 + CSP nonce + 头规范化 api/quote.js 校验 + 限流 + 转 Resend CDN 缓存 HTML 60s · 静态 1y · llms 24h __csp_report.js 违规聚合 → KV Sitemap 喂给爬虫 IndexNow 推送 + hreflang 全套 KV: rl:<ip> 每 IP 5/min 计数 + 滑动窗口 KV: dl:<id> Resend 失败回退队列 R2 / Workers Assets AVIF / WebP / PNG 源 + 多断点 浏览器 LocalStorage 语言选择 / Cookie consent 第三方仓 GA4 / AdSense / Resend / IndexNow 200 HTML (多语言) 中文用户拿中文 HTML,非 JS 翻 邮件回执 Resend 模板 · 双重副本到 admin CDN 上的图片 按 viewport 协商 AVIF→WebP→PNG /success/ 订单回执 订单号 + 后续步骤 + FAQ 链接 GA4 / CF Insights 事件 + beacon 反哺分析 ─→ 主链路 ┄→ 旁路(异步/可选) 数据形态: INPUT 原始 EDGE 中间态 DELIVER 成品 META 元数据 注:用户视频/照片本体不上 Cloudflare — 经 /api/quote 转走后,由人工/AI 在线下游处理。边缘只承载 lead 元数据 + 限流计数 + 死信。
06 · 系统组件拓扑

三个 zone · 六类节点

把上一节的"逻辑层"翻译成"物理/网络拓扑"。左边是用户和爬虫,中间是 Cloudflare 全球边缘,右边是这台 Windows 工作站 + 第三方 SaaS。所有生产流量都不进工作站,只走 deploy 时一次性把静态包推上去。

CLIENT ZONE CLOUDFLARE EDGE EXTERNAL / WORKSTATION 访客浏览器 Chrome / Safari / Firefox PWA: manifest + sw.js 离线 搜索引擎爬虫 Googlebot · Bingbot · GPTBot 拿 sitemap.xml + llms-full.txt 管理员 /admin/leads/ + DLQ_TOKEN 查死信 / 重发失败邮件 第三方 SDK gtag · AdSense · CF Insights strict-dynamic 下需被 nonce loader 拉 已废弃 PWA 客户端 老版本离线缓存(预热) CDN PoP (300+ 节点) 静态 HTML / CSS / JS / images 边缘 cache: HTML 60s, static 1y Workers runtime V8 isolates · 0ms cold start 5 个 functions 5 个 functions _middleware.js (8 步管线) · api/quote.js (POST) · api/dead-letters.js (GET/POST) · __csp_report.js (POST) · docs/[id].js (GET) KV: LEAD_STORAGE 限流 rl:<ip> · 死信 dl:<id> 强一致 · 全球 60ms 内可读 D1 / R2 (预留) 未来存成品视频/分析 暂未启用 _redirects + _headers + wrangler.toml 路由 / 安全头 / KV 绑定 / 环境变量 Workers AI / Pages 部署管线 wrangler 4.114 上传 .assetsignore 过滤后的资产 CI: .github/workflows/ci.yml (本地校验) 回滚: 任意历史 commit 重新 wrangler deploy 部署窗口: 1-3 分钟 (含 KV 同步) Windows 工作站 (qiaoshan) C:\Users\qiaoshan\.openclaw\workspace\weddingai\ 图片 pipeline + content gen + pre-deploy 本地构建工具链 根 *.py + internal-tools/*.ps1 .assetsignore 全排除, 不会被打包 scripts/ 装 python 工具 + PowerShell 入口 Pillow / Pillow-AVIF 多断点 + AVIF WebP / PNG fallback Node 20+ functions/ ESM wrangler 4.114 Cloudflare Dashboard 查 KV · 看 logs · 回滚部署 日常不登, 故障时介入 weddingai-private 仓库 AGENTS.md · CHANGELOG.md · 备份 独立 repo, 永远不上 deploy Resend (邮件) api.resend.com IndexNow + Bing api.indexnow.org HTTPS 爬 sitemap+html +DLQ_TOKEN gtag/AdSense/Insights miss 读/写 KV 发邮件 推 URL wrangler deploy (一次性)
07 · 业务流程

三个 端到端 流程

挑了三个最值钱的闭环:客户询价、内容生产 (SEO 引擎)、管理员救火。每个流程都从用户/操作员的动作开始,到系统状态变化或反馈结束。

F-01 新客询价

访客浏览 → 选 SKU → 提交表单 → 邮件回执,平均 4.2 步。

  1. 访客 浏览 /services/personalization/*/ 选 SKU
  2. CTA → /order/ 三步表单(套餐 / 资料 / 确认)
  3. POST /api/quote (Workers 接收)
  4. 校验 字段完整性 + 邮箱格式 + 反垃圾词
  5. 限流 KV rl:<ip> 5/min/IP, 超 → 429
  6. Resend 发客户确认 + 副本给 admin
  7. 成功 302 → /success/ (noindex) + GA4 event
  8. 失败 Resend 报错 → 写 KV dl:<id>, 返 200 让客户看到 /success/ (回执异步补发)

F-02 博客 SEO 引流

articles/*.md → /blog/<slug>/ → IndexNow 推送 → 搜索收录。

  1. 作者 在 articles/ 写 .md (含 front matter + body)
  2. scripts/generate-blog.py 渲染为 /blog/<slug>/index.html
  3. schema JSON-LD BlogPosting + Article + 10 语言 hreflang 注入
  4. 内链 qa/dedup_noscript.py 扫 + 修 <noscript> 重复
  5. 图片 走图片 pipeline (源图 → 多断点 + AVIF)
  6. 部署 wrangler deploy, 边缘 60s 缓存
  7. 推送 internal-tools/update-sitemap.ps1 → sitemap-zh.xml + IndexNow
  8. 收录 Googlebot 1-3 天, Bing 1-7 天, GPTBot 数小时

F-03 死信重发

Resend 失败的 lead 不丢,管理员手动重发,带 token 鉴权。

  1. 触发 /api/quote 调 Resend 返回非 2xx
  2. 落 DLQ KV dl:<leadId> 存 lead 全文 + 错误码
  3. 管理员 访问 /admin/leads/ (页面本身 public)
  4. 鉴权 输 DLQ_TOKEN → POST /api/dead-letters
  5. 列表 拿到 dl:* 全表 (按时间倒序)
  6. 重发 选 lead → POST /api/dead-letters?action=resend
  7. 校验 二次 Resend, 成功 → 删 KV key
  8. 失败 保留 KV key + 累加重试次数, 下次再试
08 · 跨服务时序(极简版)

F-01 的 5 步时间线

把 F-01 流程压成一张时序图,只看谁打谁、几号返回,极简版不画错码分支。要看完整分支往上看 F-01 卡片。

浏览器 /order/ /api/quote KV Resend 1. GET /order/ 200 HTML 2. POST /api/quote (formData) 3. get rl:<ip> count < 5 4. emails.send() 202 Accepted 5. put rl:<ip> = count+1 6. 302 → /success/ ⏱ 总耗时 典型 200-450ms (Workers 冷启动 + Resend 往返) ↳ 失败分支: Resend 错 → 写 dl:<id>, 详见 F-03
09 · 页面区块架构

一个 HTML 页 = head + nav + 8-12 个 section + footer

挑了 5 个典型页面对比:首页(信息密度最高)、服务详情(模板化最强)、博客文章(内容型)、订购(转化型)、404/offline(极简)。每列里 block 的颜色就是它的类型,看图就知道哪些页面结构相似、哪些页面是孤例。

/index.html 首页
信息密度最高 · LCP 关键页
meta + OG + JSON-LD
1. Hero · LCP 图
2. 卖点 × 3
3. 9 SKU 卡片
4. 案例视频
5. 价格预览
6. FAQ (Schema)
7. 推荐博客 × 3
8. CTA → /order/
/services/<cat>/<sku>/ 服务详情
9 个 SKU 复用同模板
Product schema
1. Hero · 服务名
2. 痛点描述
3. 流程 3-4 步
4. 案例视频
5. 3 档价格
6. FAQ
7. 关联服务 × 3
8. CTA → /order/
/blog/<slug>/ 博客文章
50+ 篇 · articles/*.md
BlogPosting schema
1. Hero · 标题+缩略
2. TOC (sticky)
3. 正文 (md 渲染)
4. 相关推荐 × 3
5. CTA → 服务
/order/ 订购
3 步表单 · 转化页
noindex + Order schema
1. 进度条 (1/3 → 3/3)
2. 套餐 (3 卡片)
3. 资料 (姓名/邮箱/留言)
4. 确认 + 提交
5. 错误态 (限流/校验)
6. 成功 → /success/
/404 · /offline 404 + 离线
极简 fallback
noindex + minimal
1. 单段 message
2. 跳转链接 (3-5 个)
↑ 整个页面就这么多
head 元素
导航
hero / LCP
内容
表单 / CTA
10 · 页面渲染生命周期

articles/foo.md用户看见的中文页面,8 步

一个页面的完整"诞生史":从内容作者写 markdown 开始,经过本地工具链注入,到 wrangler 部署,再到边缘中间件处理,最后被浏览器渲染。中间任意一步挂了,这一篇页面就废。每步都标了"谁负责"和"输入/输出"。

  1. WORKSTATION STEP 01 · SOURCE

    内容作者写源文件

    输入: articles/46-weddingai-video-review.md(含 front matter) · 原图 source-hero-1920.jpg
    输出: 一个 .md + 一组原图,放在 repo 本地
    负责: 人(你)。这一步完全离线,没碰任何 deploy 资产。

  2. WORKSTATION STEP 02 · RENDER

    渲染为静态 HTML

    输入: .md + front matter
    输出: /blog/weddingai-video-review/index.html(含 Schema.org BlogPosting JSON-LD + 10 语言 hreflang + 内嵌 OG meta)
    负责: scripts/generate-blog.py(本地 Python)

  3. WORKSTATION STEP 03 · INJECT

    图片 / CSS 注入

    输入: 上一步的 HTML + images/source-hero-1920.jpg
    输出: 同一 HTML,但 hero img 标签被改写成 <picture> + srcset(1600w/1920w)+ AVIF source,带 width/height,带 preload link
    负责: 根目录 *.py(inject-srcset / inject-avif-source / inject-dimensions / inject-critical-css)。

  4. WORKSTATION STEP 04 · CHECK

    本地 + pre-deploy 校验

    输入: 完整部署包 (整站 .html + images/ + js/ + functions/)
    输出: 1 个内部 tools pre-deploy-check.ps1 通过信号(无 404 srcset / 无硬编码 nonce / 无相对路径 / 无 /xx/ 死链)
    负责: internal-tools/pre-deploy-check.ps1(本地 PowerShell,跑 7 类检查)。

  5. WORKSTATION STEP 05 · DEPLOY

    wrangler 上传到 Cloudflare

    输入: 部署包(已 .assetsignore 过滤,private/qa/scripts/internal-tools/ 全排除)
    输出: 边缘节点拿到完整静态资产 + functions/_middleware.js 等 5 个函数
    负责: wrangler 4.114(本地执行 deploy 命令,1-3 分钟完成,含 KV 同步)。

  6. CLOUDFLARE EDGE STEP 06 · REQUEST

    用户浏览器发请求

    输入: 浏览器 GET https://weddingai.video/blog/weddingai-video-review/ · Accept-Language: zh-CN
    输出: 请求路由到最近的 Cloudflare PoP,Workers runtime 启动 _middleware.js
    负责: Cloudflare 全球 Anycast 网络 + Workers 0ms 冷启动。

  7. CLOUDFLARE EDGE STEP 07 · TRANSFORM

    边缘中间件 8 步管线

    输入: 英文 HTML 模板 + 接受语言 zh-CN
    输出: 完全中文化的 HTML(<html lang="zh-CN">、hreflang 全套、og:locale、JSON-LD inLanguage、data-i18n 全部翻译) + CSP nonce 已注入 + Content-Security-Policy 头已设置
    负责: functions/_middleware.js(详细 8 步见 s3 章节)。

  8. BROWSER STEP 08 · RENDER

    浏览器加载 + 渲染 + hydrate

    输入: 200 OK 中文 HTML + 已注入 nonce 的 <script> 标签 + styles.min.css?v=N + js/main.min.js
    输出: 用户看见完整中文页面,首屏 LCP < 1.8s,语言切换器、cookie banner、GA4 全部活起来
    负责: Chrome/Safari/Firefox + PWA service worker(sw.js 处理离线 fallback)。

关键观察: 这 8 步里只有 WORKSTATION 1-5 是你电脑上的本地操作,EDGE 6-7 是 Cloudflare 自动跑,BROWSER 8 是用户侧。任何"页面坏了"先定位在哪一步:源码错了?渲染没跑?图片没注入?pre-deploy 没拦住?上传丢了?中间件崩了?浏览器兼容?三段每段都有专门的 debug 入口。