# ADR-005 · Hybrid deployment · Cloudflare Pages (静态) + 腾讯云轻量 (API)

| 字段 | 值 |
|---|---|
| **状态** | `accepted` · 2026-05-28 |
| **日期** | 2026-05-28 |
| **决策者** | CTO + 项目主理 |
| **承接** | [ADR-003](ADR-003-deployment-as-optional.md) (deployment 三形态) · [ADR-004](ADR-004-boss-skills-as-product.md) (HTTP API product) |
| **相关** | [`docs/deployment-hybrid.md`](../deployment-hybrid.md) · [`docs/showcase/2026-05-29-hybrid-deploy.html`](../showcase/2026-05-29-hybrid-deploy.html) |

---

## 1. Context

ADR-003 提出 3 种 deployment 形态 (D1 Local / D2 Self-host / D3 GitHub Actions), ADR-004 落地 v1 HTTP API. 当用户问 "下一步发布 skills 对云服务有哪些要求, Cloudflare 能否只存静态页?" 时, 浮现出一个更细的拆分:

- **静态资源** (showcase / landing / docs / openapi.json) — 无 secret, 公开内容, 适合 CDN
- **动态 API** (boss_server.py FastAPI · subprocess attribution_check.py) — 有 secret (ANTHROPIC_API_KEY), 需 long-running process, 适合 VM
- **完整 vault** (anchors + cron + cases/reports confidential) — 数据敏感, 单租户

之前 ADR-003 的 D2 "Self-host Hermes" 把静态 + API + cron 都视为一个目标 (一台云 VM 跑 Hermes), 但实测 (本 ADR 撰写时) 发现:

| 资源类型 | 适合 host | 不适合 host |
|---|---|---|
| HTML/CSS/JS 静态 | CDN (Cloudflare Pages / Netlify / Vercel) | 自己 VM (浪费 CPU/带宽) |
| Python subprocess + secret | VM (腾讯云 / Fly.io / Render) | Cloudflare Workers (30s 时限 + 不支持 subprocess) |
| Cron + confidential data | 单租户 VM (D2) 或 GitHub Actions (D3) | CDN/Serverless |

把这些放一台 VM 是 lazy default, 不是最优。

## 2. Decision

**拆分 deployment 为分层 hybrid 架构**, 让每种资源去最适合的 host:

```
┌─ 边缘层 (静态 · 公开 · 无 secret) ─────────────────────────────┐
│  Cloudflare Pages (全球 CDN)                                  │
│    - landing.html · 5 showcase · openapi.json · README        │
│    - 自定义域名 + auto SSL · $0 · push 自动 deploy             │
└────────────────────────────────────────────────────────────────┘
                              │
                              │ 用户 click "API docs" / curl
                              ▼
┌─ 中心层 (API · 有 secret · long-running) ──────────────────────┐
│  腾讯云轻量 / Fly.io / Render (单租户 VM)                       │
│    - boss_server.py (uvicorn + 5 endpoint)                    │
│    - attribution_check.py (cron via systemd timer)            │
│    - nginx (reverse proxy + SSL + rate limit)                 │
│    - ANTHROPIC_API_KEY + .env (1Password)                     │
│    - $10-15/月 (2C2G 40GB) 或 $25/月 (2C4G 80GB)              │
└────────────────────────────────────────────────────────────────┘
                              │
                              │ Lead 调 mcp__feishu / WebSearch
                              ▼
┌─ 数据层 (confidential · 锚点 raw) ─────────────────────────────┐
│  同上 VM 内 + 本地 Mac (开发)                                  │
│    - anchors/<slug>/raw/ (gitignored)                         │
│    - cases/ reports/ (gitignored, 仅 demo 入 git)              │
│    - chmod 700, 仅 boss user                                  │
└────────────────────────────────────────────────────────────────┘
```

**与 ADR-003 的关系**: D1/D2/D3 三形态不变, 本 ADR 是 D2 的**最优化实现细节** (D2 不是"一台 VM 跑全部", 而是"VM 跑动态 + CDN 跑静态")。

## 3. Consequences

### 3.1 · 优势 (vs 全 VM)

| 维度 | hybrid | 全 VM |
|---|---|---|
| 静态访问国内速度 | Cloudflare 边缘 < 50 ms | VM 直连 > 200 ms |
| 静态访问国外速度 | < 100 ms | > 500 ms |
| 公开静态月成本 | $0 | 占 VM 带宽 (~ 20% 流量) |
| 故障耦合 | API 宕 / docs 仍活 | 一损俱损 |
| Secret 暴露面 | 仅 VM 一处 | 同上 (但静态本不需 secret) |
| CI/CD | 静态 push 自动 / API 单独 deploy | 一处 webhook 联动 |
| Cache 效率 | CDN edge cache 100% | VM 不 cache |
| Scale 上限 | 静态 ∞ / API 垂直 | VM 单点 |

### 3.2 · 接受的 tradeoff

- **多服务管理** — 但已有模板 + 文档 + DNS 集中管理 (Cloudflare 同时管两边)
- **跨 domain CORS** — boss_server.py FastAPI 加 `CORSMiddleware`, 配 1 行
- **DNS 配置略复杂** — Cloudflare DNS GUI 2 步 (`A api.boss-vault.com → vm-ip` + `CNAME www → pages.dev`)
- **2 个 SSL** — 都由 Cloudflare / certbot 自动续, 无运维负担

### 3.3 · 不变的承诺

- ADR-001 multi-anchor (anchors/<slug>/) 不变
- ADR-002 物理目录 + gitignore 不变
- ADR-003 三形态 D1/D2/D3 不变 — 本 ADR 是 D2 的**最优实现**, 不是替代
- ADR-004 boss-skills as product (v1 HTTP API) 不变 — 部署到腾讯云
- 判断质量 跨 host 一致 (5 镜头 + adversarial_view + anchor_delta)

## 4. Alternatives Considered

| 方案 | 为什么没选 |
|---|---|
| **全 Cloudflare** (Pages + Workers) | Workers 不支持 subprocess (`attribution_check.py`), 30s 时限不够 `--no-quick` mode |
| **全腾讯云一台 VM** | 静态资源 CDN 优势浪费; 国内外速度差; 单点故障 |
| **AWS / 阿里云** | 国内访问腾讯云通常更快 (用户在国内); AWS 含中国出海复杂; 阿里云价格类似无明显优势 |
| **K8s** | 单租户 + V0 期, 过度工程化; 升级路径见 §5 |
| **Vercel + Railway** | 价格类似, 国内访问 Vercel 慢; Railway 海外节点延迟高 |
| **Fly.io 全栈** | 静态资源也走应用容器, 失去 CDN 价值; 但 Fly.io 对 API 部分是好选项 |

## 5. Migration Plan

### 5.1 · 当前 (v0.3.0-rc1)

- Cloudflare Pages: 未部署
- 腾讯云轻量: 未购买
- 本地 D1 (Claude Code) 已可用

### 5.2 · Phase 1 · 静态先行 (推荐立即做, ~ 30 min, $0)

**前置 — www/ + docs/internal/ 拆分 (2026-05-28 已完成)**:

为避免内部文档 (dev-log/dev-plan/PRD/progress/audit) 与公网部署面混淆, 仓库已拆分:

- `www/` (vault root) · **CF Pages build output**, 公网可见
  - `www/index.html` (原 landing.html) · 对外门户 marketing, **首页**
  - `www/docs.html` (原文档总览)
  - `www/adr/` · 5 ADR (公开架构决策)
  - `www/api/` · openapi.json + integration cookbook
  - `www/showcase/` · 7 互动 SPA
  - `www/deployment.md` + `www/deployment-hybrid.md` + 用户/开发手册
- `docs/internal/` · 仅本地+github 可见, **不** CF deploy (不在 build path, CF 永远拿不到)
  - dev-log/ + progress/ + dev-plan*.md + prd-v3.1*.md + code-audit*.md + security-and-deidentification.md

新增 preflight: `scripts/check_public_safe.py` 在 Phase 1 接 CF 前必跑:
- 硬规则扫描 (真名 / 内部 URL), 默认 `--root www`
- 当前状态: ✅ www/ 25 文件 0 命中

部署步骤:

- [ ] **preflight**: `python3 scripts/check_public_safe.py` → 必须 PASS (0 硬规则命中)
- [ ] 注册 Cloudflare 账号 (免费)
- [ ] 接 GitHub repo zhanglunet/boss-vault
- [ ] CF Pages 设置: **build output directory = `www`** (无需 exclude — `docs/internal/` 不在 build path)
- [ ] CF 默认服务 `www/index.html` 作为首页 (= 原 landing.html marketing 内容)
- [ ] 配自定义域名 (可选, 默认 `boss-vault.pages.dev`)
- [ ] 验证: `/` → 对外门户 + 7 showcase 加载 + `/api/openapi.json` 返回 + `/docs.html` 文档总览
- [ ] dev-log 记录

详见: [`deployment-hybrid.md`](../deployment-hybrid.md) §2

### 5.3 · Phase 2 · API 上腾讯云 (按需启动, ~ 2 小时, 70-80 元/月)

**启动信号**:
- 外部 user 明确要求"我想 curl 你们 API"
- 内部团队 ≥ 3 人需要 always-on
- D3 GitHub Actions schedule 高峰延迟 (已实测 > 51 min) 影响 attribution 时效

**步骤**:
- [ ] 买腾讯云轻量 2C2G 40GB Ubuntu 22.04 (年付 ~ 70 元/月)
- [ ] SSH + 配 boss user + 装 Python 3.11 / nginx / certbot / ufw
- [ ] clone repo + pip install -r requirements.txt
- [ ] 配 .env (ANTHROPIC_API_KEY 用 1Password 或环境变量)
- [ ] cp templates/boss-hermes.service.example → /etc/systemd/system/ (注: 内部 ExecStart 已是 uvicorn boss_server)
- [ ] cp templates/nginx-boss-hermes.conf.example → /etc/nginx/sites-available/
- [ ] systemctl enable + start boss-hermes
- [ ] certbot --nginx -d api.<your-domain>
- [ ] Cloudflare DNS: `A api.<your-domain> → vm-ip` (Cloudflare proxy 关闭, 因为是 API 不需 CDN)
- [ ] curl https://api.<your-domain>/v1/healthz → 200

详见: [`docs/deployment-hybrid.md`](../deployment-hybrid.md) §3

### 5.4 · Phase 3 · 完整生产化 (推迟到 V1 后)

- 多 anchor (anchors/jobs/ anchors/musk/) — 需要 V1 评测
- 单 VM 升 4C8G 含 docker compose orchestration
- 飞书 webhook 接入 (D2 nginx 已配 `/feishu/event` 端点)
- 备份 / 监控 / 日志聚合

---

## 6. 关键反共识立场

**"hybrid 是过度工程化"** — 错。

PRD 早期假设 "single VM 跑全部 = simple"。但实测表明:
1. 静态资源 (5 showcase × 100KB) 走 Cloudflare 全球 CDN 与走 VM 直连, **国内速度差 4x, 国外差 5x**
2. 静态资源没 secret, 与 API VM 物理隔离 = **blast radius 缩小 90%**
3. 99% 流量是 docs 访问 (公开), 1% 是 API 调用 — 把 99% 放 $0 CDN 是常识, 不是过度优化

**真正的过度工程化是把所有东西都塞一台 VM**, 因为它把 "静态 CDN 优势" + "secret 隔离" 都浪费了。

---

## 7. 何时回看本 ADR

- 静态部署 (Phase 1) 完成时 → 加链接到 ADR
- API 上云 (Phase 2) 完成时 → 验证 §3.1 实测延迟数据
- 任何外部用户接入 → 更新 §5.4 真实需求 (multi-anchor / webhook)

---

*ADR-005 · accepted · 2026-05-28 · ADR 体系第 5 个 · 与 ADR-001/002/003/004 同源 product/architecture/deployment 完整 positioning*
