# 文档生产及输出管理 — 规划设计及实施方案 ## 一、概述 ### 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 导出 | 有权限用户可导出 PDF(Pandoc + 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` | 发表评论和反馈 | true(login/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` | 短链接 | 营销短信文案 | 系统默认浏览器打开 | 链接格式示例: ``` 完整 URL:https://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 周 |