Files
system-design/IT服务平台/ICT服务平台/文档生产及输出管理.md
T
jiahong e303bb868a 更新
2026-03-22 15:19:22 +08:00

960 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 文档生产及输出管理 — 规划设计及实施方案
## 一、概述
### 1.1 目标
基于 [ICT 服务平台](ICT服务平台概要.md) 的统一认证底座(OpenLDAP + Keycloak)和 Git 基础设施(Gitea),构建**从 Markdown 编写到浏览器阅读、反馈、统计分析**的全链路文档管理平台,覆盖文档生产、发布、阅读、协作、运营的完整生命周期。
### 1.2 核心设计原则
- **Git 为唯一真实源**:所有文档以 Markdown 格式存储于 Git 仓库,浏览器端为只读渲染视图
- **开源优先**:核心组件全部采用成熟开源方案,降低成本与锁定风险
- **认证复用**:登录用户接入 ICT 平台 Keycloak SSO 免密码秘钥登录;游客与访客免登录,通过浏览器指纹追踪
- **自动化驱动**:Git 推送即触发渲染、发布、同步,零人工干预
### 1.3 用户角色
| 角色 | 说明 | 典型场景 |
|------|------|---------|
| 作者 (Author) | 拥有 Git 仓库写权限的员工 | VS Code / Qoder 编写 Markdown 并推送 |
| 审阅者 (Reviewer) | 受邀阅读并点评文档的内部/外部人员 | 浏览器阅读、点评、反馈 |
| 读者 (Reader) | 通过 Keycloak 登录后访问文档的注册用户 | 登录后阅读 `login` / `restricted` 级别文档 |
| 游客 (Guest) | 免登录访问公开文档的匿名用户 | 通过 URL 自由阅读 `public` 级别文档,可匿名评论 |
| 访客 (Visitor) | 免登录仅限一次阅读的匿名用户 | 首次打开 `public_once` 级别文档可阅读,再次访问需登录 |
| 管理员 (Admin) | 管理发布策略、权限、生命周期的 IT 人员 | 配置发布规则与权限策略 |
---
## 二、系统架构
### 2.1 整体架构图
```plantuml
@startuml
skinparam componentStyle rectangle
title 文档生产及输出管理 — 系统架构
actor "作者" as Author
actor "游客/访客/读者" as Reader
node "VS Code + Qoder" as VSCode
node "互联网应用服务器 (腾讯云/阿里云)" as AppServer {
component "Nginx + SSL" as Nginx
component "Keycloak SSO" as KC
package "文档生产" {
component "Gitea" as Gitea
component "DocForge" as Forge
}
package "文档阅读" {
component "DocPortal" as Portal
component "MeiliSearch" as Search
}
package "协作与运营" {
component "Remark42" as Comment
component "Umami" as Analytics
component "MsgHub" as MsgHub
}
}
node "私有云 [数据后端]" as PCloud {
database "PostgreSQL" as DB
database "OpenLDAP" as LDAP
storage "Git 仓库存储" as Store
}
node "目标域名网站" as Sites {
component "yink.ai" as SiteA
component "docs.writech.cn" as SiteB
}
' == 作者流 ==
Author -down-> VSCode : Markdown 编写
VSCode -down-> Gitea : git push (SSH)
Gitea -down-> Store : 仓库数据
' == 渲染发布 ==
Gitea -right-> Forge : Webhook
Forge -right-> Portal : HTML + 摘要
Forge -down-> DB : 元数据入库
Forge ..> Sites : 自动部署
' == 读者流 ==
Reader -down-> Nginx : HTTPS
Nginx --> KC : 认证
Nginx --> Portal : 文档路由
' == 阅读交互 ==
Portal --> Comment : 评论
Portal --> Analytics : 访问记录
Portal --> Search : 搜索
' == 内部数据流 ==
Comment -right-> MsgHub : 评论通知
MsgHub -down-> DB : 消息存储
KC -down-> LDAP : 用户认证
@enduml
```
### 2.2 核心组件清单
| 组件 | 开源方案 | 用途 | 许可证 |
|------|---------|------|--------|
| Git 仓库 | **Gitea** | 文档源码存储与版本管理 | MIT |
| Markdown 渲染 | **Pandoc** + **markdown-it** | Markdown → HTML 转换,元数据提取 | GPL / MIT |
| 阅读平台 | **自研 DocPortal**(基于 Next.js) | 文档浏览、权限控制、URL 管理 | — |
| 评论系统 | **Remark42** | 自托管评论,支持匿名/认证评论 | MIT |
| 统计分析 | **Umami** | 自托管网站分析,页面访问与阅读时长 | MIT |
| 全文检索 | **MeiliSearch** | 文档标题、摘要、正文全文搜索 | MIT |
| PDF 导出 | **Pandoc** + **WeasyPrint** | Markdown → PDF 高质量排版 | GPL |
| 消息推送 | **自研 MsgHub**(基于 Socket.io) | 实时消息通知与任务看板集成 | — |
| 认证中心 | **Keycloak**(已有) | OIDC SSO 统一登录 | Apache 2.0 |
| 反向代理 | **Nginx**(已有) | SSL 终止、路由分发 | BSD |
| 静态站点生成 | **MkDocs** / **Hugo** | Git → 静态网站自动构建 | BSD / Apache |
| 浏览器指纹 | **FingerprintJS** (开源版) | 访客匿名标识,`public_once` 一次性阅读控制 | MIT |
---
## 三、文档生产流程
### 3.1 编写工具:VS Code + Qoder
- 作者使用 **VS Code** 编辑器 + **Qoder** AI 辅助工具进行 Markdown 文档编写
- 支持实时预览、AI 辅助补全、PlantUML 图表嵌入
- 所有文档遵循统一的 Markdown 规范(标题层级、Front Matter 元数据等)
### 3.2 Front Matter 元数据规范
每篇文档头部须包含 YAML Front Matter,声明文档元信息:
```yaml
---
title: "产品技术方案"
summary: "描述智能笔 BLE 通信协议的整体架构与关键技术细节"
author: "zhangsan@writech.cn"
tags: ["技术方案", "智能笔", "BLE"]
publish:
access: login # 可选:public / public_once / login / restricted
allowed_users: [] # access=restricted 时生效,填写用户邮箱
permissions: # 各权限开关
read: true
comment: true
save_as: false
export_pdf: false
lifecycle:
expires_at: "2026-06-30" # 可选:到期日期
max_views: null # 可选:最大阅读次数
---
```
### 3.3 Git 推送触发流程
```
作者在 VS Code / Qoder 中编写 Markdown
├─ git add → git commit → git push (SSH 秘钥认证)
└─ Gitea 接收推送
├─ Webhook → DocForge 渲染引擎
│ ├─ 解析 Front Matter 元数据
│ ├─ Markdown → HTML 渲染(Pandoc + markdown-it
│ ├─ 提取摘要(首段 / summary 字段)
│ ├─ 生成文档 URL(基于仓库路径映射)
│ ├─ 写入文档注册表(PostgreSQL
│ ├─ 推送到 MeiliSearch 索引
│ └─ 若匹配域名映射规则 → 同步到目标网站
└─ 文档在 DocPortal 即时可访问
```
---
## 四、文档渲染与发布引擎(DocForge)
### 4.1 渲染流程
DocForge 是 Git Webhook 驱动的文档处理服务,负责将 Markdown 转换为可发布的 HTML 页面:
1. **接收 Webhook**:Gitea 推送事件触发,包含变更文件列表
2. **增量渲染**:仅处理本次变更的 Markdown 文件,非全量重建
3. **元数据解析**:提取 Front Matter 中的标题、摘要、权限、生命周期配置
4. **HTML 渲染**:通过 Pandoc 将 Markdown 转为带目录的 HTML,嵌入统一样式模板
5. **摘要生成**:优先使用 `summary` 字段,未填则自动取正文前 200 字
6. **URL 生成规则**`https://docs.writech.cn/{仓库名}/{文档路径}`
7. **注册入库**:文档元数据(URL、标题、摘要、权限、生命周期)写入 PostgreSQL
8. **搜索索引**:文档标题 + 摘要 + 正文推送至 MeiliSearch
### 4.2 渲染引擎技术栈
```
DocForge (Node.js 服务)
├─ Express.js — HTTP 接收 Webhook
├─ Pandoc (CLI 调用) — Markdown → HTML 核心渲染
├─ markdown-it — 辅助渲染(代码高亮、PlantUML 等)
├─ gray-matter — Front Matter 解析
├─ pg (node-postgres) — 元数据写入 PostgreSQL
└─ meilisearch-js — 搜索索引更新
```
---
## 五、文档阅读平台(DocPortal
### 5.1 功能概览
DocPortal 是面向读者的 Web 应用,提供文档浏览、搜索、评论、导出等功能:
| 功能 | 说明 |
|------|------|
| 文档列表 | 按仓库/标签/时间浏览文档,显示标题 + 摘要 + URL |
| 全文搜索 | 基于 MeiliSearch 的标题、摘要、正文即时搜索 |
| 文档阅读 | 渲染后的 HTML 页面,带目录导航 |
| 评论反馈 | 嵌入 Remark42 评论组件,支持分段评论 |
| PDF 导出 | 有权限用户可导出 PDFPandoc + WeasyPrint |
| 另存为 | 有权限用户可下载 Markdown 原文或 HTML |
| 源文件定位 | 有编辑权限的用户可见「编辑源文件」图标,一键复制 Git 仓库中对应 Markdown 文件的完整路径 |
### 5.2 URL 与摘要体系
每篇文档发布后具备:
| 元素 | 格式 | 示例 |
|------|------|------|
| 文档 URL | `https://docs.writech.cn/{repo}/{path}` | `https://docs.writech.cn/docs/技术方案/BLE通信协议` |
| 短链接 | `https://docs.writech.cn/d/{短码}` | `https://docs.writech.cn/d/a3Kx9` |
| 摘要 | Front Matter `summary` 或自动提取前 200 字 | 显示在文档列表、搜索结果、分享卡片中 |
短链接便于在邮件、即时通讯中分享,访问短链接自动重定向到完整 URL。
### 5.3 源文件快速定位(编辑图标)
对于拥有 Git 仓库写权限的用户,文档页面右上角显示 **「✏️ 编辑源文件」** 图标:
- **点击**:复制 Git 仓库中对应 Markdown 文件的完整路径到剪贴板,如 `docs/技术方案/BLE通信协议.md`
- **Tooltip**:显示仓库名 + 文件路径 + 最近修改者 + 修改时间
- 作者可直接在 VS Code / Qoder 中通过路径定位文件并修改
---
## 六、权限管理体系
### 6.1 文档访问级别
文档发布时,作者在 Front Matter 的 `publish.access` 字段选择访问级别:
| 级别 | 标识 | 说明 |
|------|------|------|
| **公开** | `public` | 游客可通过 URL 自由访问,无需登录,不限次数 |
| **公开一次** | `public_once` | 访客免登录可阅读一次,再次访问同一文档需登录;通过浏览器指纹 + Cookie 判定 |
| **需登录** | `login` | 需通过 Keycloak 登录后方可访问(读者 / 审阅者) |
| **限定人员** | `restricted` | 仅 `allowed_users` 列表中的用户可访问 |
### 6.2 细粒度权限矩阵
`publish.permissions` 中按功能逐项配置:
| 权限 | 说明 | 默认值 |
|------|------|--------|
| `read` | 阅读文档正文 | true |
| `comment` | 发表评论和反馈 | truelogin/restricted);public 游客可匿名评论(需验证码);public_once 访客不可评论 |
| `save_as` | 下载 Markdown 原文或 HTML | false(游客 / 访客始终不可用) |
| `export_pdf` | 导出为 PDF 文件 | false(游客 / 访客始终不可用) |
### 6.3 权限校验流程
```plantuml
@startuml
skinparam componentStyle rectangle
title 文档访问权限校验流程
start
:用户访问文档 URL;
if (文档 access = public ?) then (是)
:允许阅读;
note right: 游客 - 免登录, 不限次数
else (否)
if (文档 access = public_once ?) then (是)
if (用户已登录 ?) then (是)
:允许阅读;
note right: 登录用户不受一次限制
else (否)
:生成浏览器指纹;
if (已有该文档访问记录 ?) then (是)
:提示 "请登录后继续访问";
:重定向到 Keycloak 登录;
stop
else (否)
:允许阅读;
:写入指纹记录 + Cookie;
note right: 访客 - 免登录, 仅此一次
endif
endif
else (否)
if (用户已登录 Keycloak ?) then (否)
:重定向到 Keycloak 登录;
stop
else (是)
if (文档 access = login ?) then (是)
:允许阅读;
else (restricted)
if (用户在 allowed_users 列表中 ?) then (是)
:允许阅读;
else (否)
:返回 403 无权访问;
stop
endif
endif
endif
endif
endif
:加载文档页面;
:根据角色与 permissions 决定功能可用性;
note right
游客: 可匿名评论(需验证码), 不可导出
访客: 不可评论, 不可导出
登录用户: 按 permissions 配置
编辑图标: 仅 Git 写权限用户
end note
stop
@enduml
```
### 6.4 权限与认证底座的关系
| 层次 | 组件 | 职责 |
|------|------|------|
| 身份源 | OpenLDAP(私有云) | 用户账户、组织架构、角色 |
| 认证中心 | Keycloak(互联网服务器) | SSO 登录,签发 OIDC Token |
| 匿名访问控制 | DocPortal + FingerprintJS | 游客自由访问 `public` 文档;访客通过浏览器指纹 + Cookie 判定是否首次访问 `public_once` 文档 |
| 应用层权限 | DocPortal | 解析登录用户 Token 或匿名身份,匹配 Front Matter 权限配置 |
| Git 写权限 | Gitea | 判断用户是否有仓库写权限,控制「编辑图标」显示 |
### 6.5 访客一次性阅读的技术实现
`public_once` 级别文档的访客身份追踪方案:
| 技术手段 | 说明 |
|---------|------|
| FingerprintJS | 客户端浏览器指纹库,生成稳定的匿名标识符(无需 Cookie 即可识别回访) |
| HttpOnly Cookie | 辅助手段,首次阅读时种下 Cookie,防止清除指纹后绕过限制 |
| 服务端记录 | PostgreSQL 存储 `(fingerprint_hash, doc_id, visited_at)`,校验是否已阅读 |
校验流程:用户访问 `public_once` 文档时,DocPortal 前端通过 FingerprintJS 生成浏览器指纹,携带指纹向后端查询是否已有该文档的访问记录;无记录则放行并写入,有记录则提示登录。
> **注意**:浏览器指纹并非 100% 可靠(更换浏览器或隐身模式可重置),`public_once` 的定位是**轻量防护**,适用于营销试读、内容预览等场景。高价值内容建议使用 `login` 或 `restricted` 级别。
---
## 七、阅读统计分析
### 7.1 采集指标
基于 **Umami**(自托管 Web 分析)采集以下数据:
| 指标 | 采集方式 | 说明 |
|------|---------|------|
| 页面访问量(PV | Umami JS 埋点 | 每次打开文档 URL 计一次 |
| 独立访客数(UV) | Umami 匿名指纹 | 去重统计独立访问用户(含游客 / 访客匿名指纹) |
| 阅读时长 | Umami 页面停留时间 + 自定义心跳事件 | 每 30 秒上报一次心跳,计算有效阅读时长 |
| 阅读进度 | 自定义事件(滚动百分比) | 记录用户阅读到文档的哪个位置 |
| 来源渠道 | Umami Referrer | 记录用户从哪个链接进入 |
### 7.2 阅读时长精确统计方案
标准的页面停留时间统计不够准确(用户可能切出标签页),采用**心跳 + 可见性检测**方案:
```javascript
// 嵌入文档页面的阅读时长统计脚本(伪代码)
let readingSeconds = 0;
let heartbeatTimer = null;
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
clearInterval(heartbeatTimer); // 页面不可见,暂停计时
} else {
heartbeatTimer = setInterval(() => {
readingSeconds += 30;
umami.track('reading-heartbeat', { // 每30秒上报
doc_id: DOC_ID,
seconds: readingSeconds
});
}, 30000);
}
});
```
### 7.3 统计看板
管理员和作者可在 DocPortal 中查看文档统计看板:
- **文档维度**:每篇文档的 PV / UV / 平均阅读时长 / 完读率
- **时间维度**:按日 / 周 / 月查看趋势
- **用户维度**:(需登录文档)哪些用户阅读了、阅读时长排名
- **导出**:统计数据可导出 CSV
---
## 八、文档生命周期管理
### 8.1 生命周期配置
在 Front Matter 的 `publish.lifecycle` 中配置:
| 参数 | 类型 | 说明 |
|------|------|------|
| `expires_at` | 日期字符串 | 到期后文档自动下架,页面显示「文档已过期」 |
| `max_views` | 整数 | 累计阅读次数达到上限后自动下架 |
| 无配置 | — | 永久有效,不自动下架 |
> **区分 `max_views` 与 `public_once`**`max_views` 是文档级总阅读次数上限(达到后所有用户均不可访问),`public_once` 是访客级单次阅读限制(每位访客仅限免登录阅读一次,登录用户不受影响)。两者可同时配置、互不冲突。
### 8.2 生命周期状态流转
```
已发布 (Active)
├─ 达到 expires_at → 已过期 (Expired)
├─ 达到 max_views → 已达上限 (Limit Reached)
├─ 作者手动下架 → 已下架 (Archived)
└─ Git 中删除文件 → 已删除 (Deleted)
已过期 / 已达上限 / 已下架
└─ 作者更新 Front Matter 重新配置 → 已发布 (Active)
```
### 8.3 下架处理
- 下架后 URL 仍保留,但页面显示提示信息(如「此文档已过期,请联系作者」)
- 管理员可配置是否允许已登录用户查看过期文档的历史快照
- 文档的统计数据和评论不随下架删除,可供作者回溯
---
## 九、评论反馈系统
### 9.1 技术方案:Remark42
采用 **Remark42** 自托管评论系统:
- **部署位置**:互联网应用服务器(Docker 容器)
- **认证对接**:通过 Keycloak OIDC 实现评论者身份认证
- **匿名评论**`public` 级别文档支持游客匿名评论(需验证码防刷);`public_once` 级别文档访客不开放评论
- **数据存储**Remark42 自带 BoltDB 存储,备份至私有云
### 9.2 评论功能
| 功能 | 说明 |
|------|------|
| 文档级评论 | 在文档末尾发表整体评论 |
| 段落级评论 | 选中文档段落后发表针对性评论 |
| 回复与嵌套 | 支持多级回复讨论 |
| @提及 | 评论中 @某用户,触发专属通知 |
| Markdown 格式 | 评论内容支持 Markdown 语法 |
| 管理操作 | 作者可置顶、删除评论;管理员可全局管理 |
### 9.3 评论触发消息通知
当文档收到新评论或反馈时:
1. Remark42 通过 Webhook 通知 MsgHub 消息中心
2. MsgHub 根据评论内容识别通知目标:
- 文档作者(始终通知)
-@提及的用户
- 该文档评论帖的参与者(可配置是否通知)
3. 消息实时推送到目标用户的消息中心
---
## 十、消息中心与任务看板集成
### 10.1 设计理念
消息中心采用**类微信群列表**的交互模式:
- 每篇有新消息的文档如同一个「对话」
- 新消息驱动该文档条目**置顶排列**(最新消息在最前)
- 点击文档条目直接在浏览器中打开对应文档及其评论区
- 未读消息显示红点 + 未读数
- 消息中心同时作为作者的**任务看板**,待处理的评论/反馈一目了然
### 10.2 消息类型
| 消息类型 | 触发条件 | 消息内容 |
|---------|---------|---------|
| 📝 新评论 | 文档收到新评论 | "{用户}在《{文档标题}》中发表了评论" |
| 💬 回复 | 某人回复了你的评论 | "{用户}回复了你在《{文档标题}》中的评论" |
| @提及 | 评论中 @了你 | "{用户}在《{文档标题}》的评论中提到了你" |
| 📊 阅读里程碑 | 文档阅读量突破阈值 | "《{文档标题}》阅读量已突破 100 次" |
| ⚠️ 生命周期告警 | 文档即将过期或达到阅读上限 | "《{文档标题}》将于 3 天后过期" |
### 10.3 消息中心界面结构
```
┌─────────────────────────────────────────┐
│ 📬 消息中心 🔍 搜索 │
├─────────────────────────────────────────┤
│ 🔴 BLE通信协议技术方案 10:32 │
│ 张三:建议补充低功耗模式的说明 │
├─────────────────────────────────────────┤
│ 🔴 产品需求文档 v2.1 09:15 │
│ 李四 回复了你的评论 │
├─────────────────────────────────────────┤
│ 智能笔固件升级指南 昨天 │
│ 阅读量已突破 100 次 │
├─────────────────────────────────────────┤
│ Q3 项目计划 周一 │
│ 王五:时间节点需要再确认 │
└─────────────────────────────────────────┘
```
- 红点标识未读消息
- 列表按最新消息时间倒序排列
- 点击任一条目 → 浏览器打开该文档页面,自动滚动到对应评论
- 支持标记已读、批量已读、按类型筛选
### 10.4 技术实现
```
MsgHub 消息中心 (Node.js)
├─ Socket.io — WebSocket 实时推送
├─ PostgreSQL — 消息持久化存储
├─ Redis — 未读计数缓存、在线状态
├─ Remark42 Webhook — 评论事件接入
├─ DocForge Webhook — 生命周期事件接入
└─ Umami API — 阅读量里程碑检测
```
---
## 十一、域名网站自动发布
### 11.1 映射机制
Git 仓库中的 Markdown 可配置自动发布到指定域名网站,映射关系存储于 PostgreSQL
| Git 仓库 / 路径 | 目标域名 | 构建工具 | 说明 |
|-----------------|---------|---------|------|
| `web-doc/` | yink.ai | Hugo | 品牌官网内容 |
| `docs/对外文档/` | docs.writech.cn | MkDocs | 对外技术文档站 |
| `edu-doc/` | edu.writech.cn | MkDocs | 教育平台文档 |
### 11.2 自动发布流程
```plantuml
@startuml
skinparam componentStyle rectangle
title Git → 域名网站自动发布流程
start
:作者 git push 更新 Markdown;
:Gitea Webhook 触发 DocForge;
:DocForge 检查变更文件路径;
if (匹配域名映射规则 ?) then (是)
:调用对应构建工具\n(Hugo / MkDocs);
:生成静态 HTML 站点;
:通过 rsync + SSH\n部署到目标服务器;
:目标域名网站内容更新;
else (否)
:仅更新 DocPortal\n内部阅读平台;
endif
stop
@enduml
```
### 11.3 映射配置文件
映射关系通过 Git 仓库中的配置文件 `.docforge.yml` 管理:
```yaml
# .docforge.yml — 仓库根目录
site_mappings:
- source: "对外文档/"
target:
domain: "docs.writech.cn"
builder: "mkdocs"
deploy:
method: "rsync"
host: "106.55.191.177"
path: "/var/www/docs.writech.cn/"
- source: "/"
target:
domain: "docs.writech.cn"
builder: "mkdocs"
base_path: "/internal/"
deploy:
method: "rsync"
host: "106.55.191.177"
path: "/var/www/docs.writech.cn/internal/"
```
映射关系一旦设定,后续 Markdown 更新即自动推送到对应域名,无需手动操作。
---
## 十二、互联网推广与海报链接体系
### 12.1 设计目标
将文档系统产出的内容转化为**互联网营销落地页**(海报链接),通过主流流量平台分发,获取 2B / 2C 新客户。核心链路:
```
文档系统 (Markdown)
├─ DocForge 渲染为静态 HTML 落地页
├─ 内嵌 JS 与服务器 API 交互(埋点 / 表单 / 动态内容)
├─ CDN 全网加速分发
├─ 生成海报链接(短链接 + 渠道追踪参数)
└─ 投放到微信 / 淘宝 / 美团 / 抖音 / 短信
└─ 客户点击/扫码 → 浏览器打开落地页 → 转化
```
### 12.2 海报链接架构
#### 落地页结构
海报链接指向的是一张**静态 HTML 落地页**,由 DocForge 从 Markdown 源文档自动生成,包含:
| 层次 | 内容 | 说明 |
|------|------|------|
| 静态 HTML | 产品介绍、图文排版、CTA 按钮 | CDN 分发,毫秒级加载 |
| 内嵌 JS | 埋点脚本 + 交互逻辑 | 页面加载后调用服务器 API |
| 服务器 API | 渠道统计、表单提交、动态内容 | 运行在互联网应用服务器 |
#### 落地页内嵌 JS 交互能力
静态落地页加载后,内嵌的 JS 脚本自动调用服务器接口完成以下交互:
```javascript
// 落地页内嵌 JS 核心逻辑(伪代码)
document.addEventListener('DOMContentLoaded', () => {
// 1. 渠道来源埋点 — 记录用户从哪个平台进入
const params = new URLSearchParams(location.search);
fetch('/api/promo/track', {
method: 'POST',
body: JSON.stringify({
page_id: PAGE_ID,
channel: params.get('ch'), // wx / tb / mt / dy / sms
campaign: params.get('cmp'), // 活动标识
referer: document.referrer
})
});
// 2. 动态内容加载 — 价格、库存、活动信息
fetch('/api/promo/dynamic/' + PAGE_ID)
.then(r => r.json())
.then(data => {
document.getElementById('price').textContent = data.price;
document.getElementById('stock').textContent = data.stock;
});
// 3. 表单提交 — 客户留资 / 咨询 / 预约
document.getElementById('lead-form').addEventListener('submit', (e) => {
e.preventDefault();
fetch('/api/promo/lead', {
method: 'POST',
body: new FormData(e.target)
});
});
});
```
### 12.3 CDN 全网加速分发
落地页为纯静态 HTML + CSS + JS + 图片,通过 CDN 分发到全网边缘节点,确保各渠道用户点击后毫秒级加载:
| 项目 | 方案 | 说明 |
|------|------|------|
| CDN 服务 | 阿里云 CDN | 覆盖国内及海外节点,配合已有域名架构 |
| 源站 | 互联网应用服务器 | DocForge 生成的静态文件存储于源站 |
| 缓存策略 | HTML 5分钟 / 图片字体 30 天 | HTML 短缓存确保内容更新及时生效 |
| HTTPS | ZeroSSL 通配符证书 | 复用 ICT 平台证书体系 |
| 缓存刷新 | DocForge 发布后自动调用 CDN Purge API | Markdown 更新后落地页即时刷新 |
发布流程:
```
DocForge 渲染落地页 HTML
├─ 写入源站目录 /var/www/promo/
├─ 调用阿里云 CDN Purge API 刷新缓存
└─ 全网边缘节点同步更新(秒级)
```
### 12.4 五大渠道投放方案
每个渠道生成专属海报链接,带渠道追踪参数,确保来源可精确归因:
| 渠道 | 渠道码 | 链接形式 | 投放载体 | 打开方式 |
|------|---------|---------|---------|----------|
| **微信** | `ch=wx` | 短链接 + 二维码 | 朋友圈图文、公众号文章、群聊卡片 | 微信内置浏览器打开 |
| **淘宝** | `ch=tb` | 淘口令 + 短链接 | 商品详情页、店铺首页、客服消息 | 手淘内置浏览器打开 |
| **美团** | `ch=mt` | 短链接 | 店铺介绍、团购详情、评价回复 | 美团 App 内置浏览器打开 |
| **抖音** | `ch=dy` | 短链接 | 视频评论区、主页链接、直播间小黄车 | 抖音内置浏览器打开 |
| **短信** | `ch=sms` | 短链接 | 营销短信文案 | 系统默认浏览器打开 |
链接格式示例:
```
完整 URLhttps://go.writech.cn/p/smart-pen-intro?ch=wx&cmp=2026q1
短链接: https://go.writech.cn/s/Xk9mP
淘口令: ¥smart-pen-introXk9mP¥
二维码: 将短链接编码为 QR Code,嵌入海报图片
```
### 12.5 渠道适配与浏览器兼容
各平台客户端点击链接后均通过其**内置浏览器**打开落地页,需针对性适配:
| 内置浏览器 | 特征 | 适配策略 |
|-------------|------|----------|
| 微信 WebView | 不支持部分 Web API,有 JS-SDK | 检测 UA 含 "MicroMessenger",加载微信 JS-SDK,启用分享卡片自定义 |
| 淘宝 WebView | 限制外跳,访问受限 | 落地页自包含,避免外跳;表单交互在页内完成 |
| 美团 WebView | 与标准浏览器接近 | 标准响应式适配即可 |
| 抖音 WebView | 限制外跳,支持基础 Web API | 落地页自包含;复杂交互引导“用浏览器打开” |
| 系统浏览器 (短信) | 完整 Web 能力 | 无需特殊适配 |
落地页 JS 自动检测运行环境并适配:
```javascript
// 环境检测与适配(伪代码)
const ua = navigator.userAgent;
if (/MicroMessenger/i.test(ua)) {
loadWxJSSDK(); // 加载微信 JS-SDK,配置分享卡片
} else if (/AliApp.*TB/i.test(ua)) {
disableExternalLinks(); // 淘宝内禁止外跳
} else if (/aweme/i.test(ua)) {
showOpenInBrowser(); // 抖音内显示“用浏览器打开”引导
}
```
### 12.6 推广流量追踪与转化分析
#### 追踪参数体系
每个海报链接携带统一追踪参数,全部流入 Umami 统计平台:
| 参数 | 说明 | 示例 |
|------|------|------|
| `ch` | 渠道来源 | wx / tb / mt / dy / sms |
| `cmp` | 活动标识 | 2026q1 / summer-sale |
| `ct` | 内容类型 | product / article / event |
| `kw` | 关键词(付费投放时) | smart-pen / ink-screen |
#### 转化漏斗
从点击到转化的全链路数据均录入 PostgreSQL,供营销团队分析:
```
点击链接 (Impression)
├─ 打开落地页 (PageView) ← Umami 埋点
├─ 页面停留 > 10s (Engaged) ← 心跳上报
├─ 提交表单 / 点击 CTA (Lead) ← 表单提交 API
└─ 完成购买 / 注册 (Conversion) ← 业务系统回调
```
#### 推广效果看板
在 DocPortal 管理后台提供推广效果看板:
| 维度 | 指标 |
|------|------|
| 渠道维度 | 各渠道 PV / UV / 平均停留 / 留资数 / 转化率 |
| 内容维度 | 各落地页访问量 / 转化率 / 热度图 |
| 活动维度 | 各活动投入产出比 (ROI) |
| 时间维度 | 按日 / 周 / 月的流量与转化趋势 |
### 12.7 推广落地页生成与管理流程
```plantuml
@startuml
skinparam componentStyle rectangle
title 推广落地页生成与分发流程
start
:营销人员在 Markdown 中编写推广内容;
note right: 使用 promo 模板,配置表单/CTA
:设置 Front Matter 推广配置;
note right
publish.type: promo
publish.channels: [wx, tb, dy]
publish.cdn: true
end note
:git push 推送到 Gitea;
:DocForge 渲染生成静态落地页;
note right
内嵌埋点 JS + 表单交互 JS
生成各渠道专属短链接
微信渠道额外生成 QR Code
end note
:部署到源站 + CDN 刷新;
:营销人员获取各渠道链接;
note right
微信: 短链接 + QR Code
淘宝: 淘口令 + 短链接
美团: 短链接
抖音: 短链接
短信: 短链接
end note
:投放到各平台;
:客户点击/扫码;
:平台内置浏览器打开落地页;
note right
CDN 加速加载静态 HTML
JS 调用服务器 API 记录渠道+加载动态内容
end note
:客户浏览/交互/留资;
:Umami + API 记录全链路数据;
stop
@enduml
```
### 12.8 推广文档 Front Matter 扩展
推广类文档在标准 Front Matter 基础上增加推广专属配置:
```yaml
---
title: "智能笔新品发布"
summary: "自然写 Qink 智能笔,笔迹实时同步至大屏"
author: "marketing@writech.cn"
tags: ["推广", "智能笔", "Qink"]
publish:
type: promo # 推广类型文档
access: public # 推广页通常 public;高价值预览内容可用 public_once
cdn: true # 启用 CDN 分发
channels: [wx, tb, mt, dy, sms] # 投放渠道
landing_page:
template: product # 落地页模板:product / article / event
cta_text: "立即了解" # CTA 按钮文案
cta_url: "/contact" # CTA 跳转目标
form: true # 是否包含留资表单
lifecycle:
expires_at: "2026-06-30"
---
```
---
## 十三、部署方案
### 13.1 服务部署清单
全部服务运行于**互联网应用服务器**(腾讯云 / 阿里云),数据后端在私有云:
| 服务 | 部署方式 | 运行位置 | 端口 |
|------|---------|---------|------|
| DocForge 渲染引擎 | Docker | 互联网应用服务器 | 3001 |
| DocPortal 阅读平台 | Docker (Next.js) | 互联网应用服务器 | 3000 |
| Remark42 评论系统 | Docker | 互联网应用服务器 | 8080 |
| Umami 统计分析 | Docker | 互联网应用服务器 | 3002 |
| MeiliSearch 搜索 | Docker | 互联网应用服务器 | 7700 |
| MsgHub 消息中心 | Docker (Node.js) | 互联网应用服务器 | 3003 |
| Redis | Docker | 互联网应用服务器 | 6379 |
| PostgreSQL | 原生安装 | 私有云 | 5432 |
| Gitea | Docker(已有) | 互联网应用服务器 | 22/443 |
| Keycloak | Docker(已有) | 互联网应用服务器 | 8443 |
| PromoAPI 推广接口 | Docker (Node.js) | 互联网应用服务器 | 3004 |
| 阿里云 CDN | SaaS | 全网边缘节点 | — |
### 13.2 Nginx 路由规则
```nginx
# DocPortal 阅读平台
location /docs/ {
proxy_pass http://127.0.0.1:3000;
}
# Remark42 评论 API
location /api/comment/ {
proxy_pass http://127.0.0.1:8080;
}
# Umami 统计
location /api/analytics/ {
proxy_pass http://127.0.0.1:3002;
}
# MeiliSearch 搜索
location /api/search/ {
proxy_pass http://127.0.0.1:7700;
}
# MsgHub WebSocket
location /ws/msg/ {
proxy_pass http://127.0.0.1:3003;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# DocForge Webhook(仅允许 Gitea 内部调用)
location /hook/docforge {
allow 127.0.0.1;
deny all;
proxy_pass http://127.0.0.1:3001;
}
# PromoAPI 推广接口
location /api/promo/ {
proxy_pass http://127.0.0.1:3004;
}
# 推广落地页静态文件(CDN 回源)
location /p/ {
alias /var/www/promo/;
expires 5m;
}
```
---
## 十四、实施路线图
| 阶段 | 任务 | 预计周期 |
|------|------|--------|
| **第一阶段:基础** | DocForge 渲染引擎开发,Gitea Webhook 对接 | 第 1-2 周 |
| **第一阶段** | DocPortal 阅读平台 MVP(文档列表 + 阅读 + URL + 摘要) | 第 2-3 周 |
| **第一阶段** | MeiliSearch 全文检索集成 | 第 3 周 |
| **第一阶段** | Front Matter 权限解析 + Keycloak OIDC 认证对接 | 第 3-4 周 |
| **第二阶段:协作** | Remark42 评论系统部署与 Keycloak 对接 | 第 5 周 |
| **第二阶段** | MsgHub 消息中心开发(WebSocket + 消息列表) | 第 5-6 周 |
| **第二阶段** | 消息中心与任务看板集成(类微信列表交互) | 第 6-7 周 |
| **第二阶段** | 评论通知 → 消息中心 → 打开文档全链路打通 | 第 7 周 |
| **第三阶段:运营** | Umami 统计分析部署,阅读时长精确统计方案 | 第 8 周 |
| **第三阶段** | 文档生命周期管理(过期、阅读上限、自动下架) | 第 8-9 周 |
| **第三阶段** | PDF 导出功能(Pandoc + WeasyPrint | 第 9 周 |
| **第四阶段:发布** | 域名网站自动发布(.docforge.yml 映射 + Hugo/MkDocs 构建) | 第 10-11 周 |
| **第四阶段** | 统计看板(作者维度 + 文档维度 + 趋势图) | 第 11-12 周 |
| **第四阶段** | 全链路测试与上线 | 第 12 周 |
| **第五阶段:推广** | 推广落地页模板开发 + CDN 接入 | 第 13 周 |
| **第五阶段** | 五渠道海报链接生成 + 渠道埋点 + 浏览器适配 | 第 13-14 周 |
| **第五阶段** | 推广效果看板(渠道归因 + 转化漏斗) | 第 14 周 |