> For the complete documentation index, see [llms.txt](https://assemble.gitbook.io/assemble/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://assemble.gitbook.io/assemble/assemble_workflow.md).

# Assemble 工作流架构

> 最后更新：2026-04-20\
> 状态：✅ 已跑通，事件驱动链路生效

本文档分两层：

* **抽象层**：Assemble 的 4 阶段概念模型（稳定，指导设计）
* **具体层**：当前的事件驱动实现（会随技术选型演变）

***

## 抽象层：Assemble 的 4 阶段概念模型

Assemble 的核心是把零散信息经过加工沉淀为可传播的内容。整个流程由 4 个阶段构成：

```
┌──────────────┐    ┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│   hunting    │ ─→ │  processing  │ ─→ │   archive    │ ─→ │   publish    │
│   搜集信息   │    │   处理加工   │    │   存档成果   │    │   发布传播   │
└──────────────┘    └──────────────┘    └──────────────┘    └──────────────┘
      输入               转化                沉淀                扩散
```

| 阶段             | 职责              | 产出               |
| -------------- | --------------- | ---------------- |
| **hunting**    | 从外部源搜集原始信息      | 原始数据（新闻、笔记、RSS…） |
| **processing** | 筛选、提炼、加工、加入你的视角 | 可发布的内容草稿         |
| **archive**    | 长期存档已定稿的内容      | 结构化的历史沉淀（可被外部引用） |
| **publish**    | 分发到目标平台         | 触达读者的最终形态        |

### 为什么要区分这 4 个阶段

* **hunting 和 processing 分开**：避免"边搜边写"的混乱。先广撒网，再精挑。
* **processing 和 archive 分开**：区分"正在编辑"和"已经定版"。未定版的内容不应污染历史。
* **archive 和 publish 分开**：同一份内容可能分发到多个平台，archive 是单一真相源。

### 每个阶段的当前实现

| 阶段         | 当前实现                                                                    | 可演进方向                           |
| ---------- | ----------------------------------------------------------------------- | ------------------------------- |
| hunting    | 从 `qiao-925/news-digest` 拉取（`run_news_loop.py`）                         | 接入 One-Note、RSS 白名单、个人笔记等       |
| processing | `assemble-processing/assemble-archive/` 本地编辑 + `publish_pipeline.py` 渲染 | 加入 AI 辅助筛选、质量评分、模板化加工           |
| archive    | `qiao-925/assemble-archive` 仓库                                          | 保持不变，作为单一真相源                    |
| publish    | GitHub Actions → 博客园（MetaWeblog）                                        | 扩展 GitHub Pages / Notion / 其他平台 |

**抽象层稳定，具体层可替换**。换一个 hunting 源或 publish 目标，都不影响整体架构。

***

## 具体层：当前的事件驱动链路

每个具体节点右侧标注它对应的抽象阶段：

```
┌──────────────────┐
│   news-digest    │  ← [hunting]      外部聚合源（独立更新）
│ (qiao-925/news-digest) │
└────────┬─────────┘
         │  ⚠ 人工 checkpoint（不自动）
         │  运行 run_news_loop.py 或手动编辑
         ▼
┌─────────────────────────────┐
│     Assemble (私有)         │  ← [processing]  编辑、处理中心
│  assemble-archive/ 目录      │                  你在这里整理内容
└────────┬────────────────────┘
         │  git push（你主动触发）
         │  Action: Assemble Archive Sync
         ▼
┌──────────────────┐
│ assemble-archive │  ← [archive]      公开成果归档
│    (公开)        │
└────────┬─────────┘
         │  push event 自动触发
         │  Action: Publish to CNBlogs
         ▼
┌──────────────────┐
│     博客园       │  ← [publish]      触达读者
└──────────────────┘
```

## 仓库职责

| 仓库                             | 可见性 | 职责                                        | 本地路径                                      |
| ------------------------------ | --- | ----------------------------------------- | ----------------------------------------- |
| `qiao-925/news-digest`         | 公开  | 外部输入源（广覆盖新闻聚合）                            | —                                         |
| `qiao-925/assemble-processing` | 私有  | 编辑、加工、触发发布的中心（本地目录仍叫 `Assemble`）          | `c:/Users/nonep/Desktop/Assemble`         |
| `qiao-925/assemble-archive`    | 公开  | 发布内容的归档仓库                                 | `c:/Users/nonep/Desktop/assemble-archive` |
| `qiao-925/assemble-publish`    | 公开  | 博客园同步脚本（被 assemble-archive 的 workflow 引用） | `c:/Users/nonep/Desktop/assemble-publish` |

## 目录结构

### Assemble 仓库

```
Assemble/
├── assemble-archive/          ← 你编辑内容的地方（一个工作目录）
│   ├── daily/<date>/*.md
│   ├── latest.md
│   └── latest.json
├── v3.0/workspace/
│   ├── scripts/
│   │   ├── run_news_loop.py        # 从 news-digest 拉取、生成产物（本地人工运行）
│   │   └── publish_output_repo.py  # 推送 assemble-archive/ 到远程仓库（workflow 调用）
│   └── src/
│       ├── news_digest_import.py   # 拉取解析 news-digest
│       ├── publish_pipeline.py     # 渲染 Markdown
│       └── output_repo_sync.py     # 同步整个 archive 目录到远程
└── .github/workflows/
    └── assemble-archive-sync.yml   # push 到 assemble-archive/ 时自动同步
```

### assemble-archive 仓库

```
assemble-archive/
├── daily/<date>/*.md
├── latest.md / latest.json
├── README.md
└── .github/workflows/
    └── publish-to-cnblogs.yml      # push 到 daily/ 时自动发布
```

## 自动化机制

### 触发链

| 环节                         | 触发条件                              | 执行者            |
| -------------------------- | --------------------------------- | -------------- |
| **编辑内容**                   | 手动                                | 你              |
| **push 到 Assemble**        | 手动                                | 你              |
| **Archive Sync**           | push event（`assemble-archive/**`） | GitHub Actions |
| **Publish to CNBlogs**     | push event（`daily/**`）            | GitHub Actions |
| **news-digest → Assemble** | ⚠ 非自动，需要人工 checkpoint             | 你              |

### GitHub 配置

**assemble-processing 仓库**

* `vars.ASSEMBLE_OUTPUT_REPO` = `qiao-925/assemble-archive`
* `secrets.ASSEMBLE_OUTPUT_PAT` = fine-grained PAT
  * 对 `assemble-archive` 需要：**Contents: Read and write + Actions: Read and write**
  * Actions 权限是必须的，否则 push 不会触发下游 workflow

**assemble-archive 仓库**

* `secrets.CNBLOGS_RPC_URL`
* `secrets.CNBLOGS_USERNAME`
* `secrets.CNBLOGS_TOKEN`

## 关键设计决策

### 为什么 news-digest → Assemble 不自动？

需要人工 checkpoint — 不是所有新闻都要转成博客。这一步涉及内容筛选、整理、润色，是价值密度的关键节点，不该自动化。

### 为什么 Assemble 内嵌 assemble-archive/ 目录？

让 "编辑内容" 和 "推送触发" 在同一个 git 操作里完成。避免跨仓库切换，也让整个处理过程可审阅。

### 为什么由 assemble-archive 的 workflow 调用 assemble-publish 的脚本？

* 脚本源码留在 `assemble-publish`（单一真相源）
* 执行发生在 `assemble-archive`（有 archive 内容 + CNBlogs secrets）
* 通过 `actions/checkout` 克隆 `assemble-publish` 到临时目录 `_publish/` 使用

### 为什么不用 Zeabur 了？

Zeabur 之前是轮询（每 12 小时），延迟大。GitHub Actions 事件驱动，秒级响应。 Zeabur 服务目前还在跑但已冗余，可下线。

## 日常操作

### 发一篇新文章

```powershell
# 1. 在 Assemble/assemble-archive/daily/<date>/ 下编辑 Markdown
# 2. push
cd c:\Users\nonep\Desktop\Assemble
git add assemble-archive/
git commit -m "publish: <title>"
git push
# 3. 等 1~2 分钟，文章就到博客园了
```

### 排查失败

* **Archive Sync 失败**：`gh run view --repo qiao-925/assemble-processing`
* **Publish 失败**：`gh run view --repo qiao-925/assemble-archive`
* **PAT 权限问题**：<https://github.com/settings/tokens?type=beta>

## 历史遗留

* `Assemble/v1.0/`、`v2.0/`：早期版本，保留不动
* `assemble-publish` 的 Dockerfile、`run_sync_hourly.py`：Zeabur 遗留，待清理
* Zeabur 服务：可下线
