Skip to content

Latest commit

 

History

History
1163 lines (833 loc) · 40.4 KB

File metadata and controls

1163 lines (833 loc) · 40.4 KB

BestBlogs Architecture

更新时间:2026-05-19
状态:v2.4.0 重写草案(承接 VISION + PRODUCT + BRAND v2)

本文档承接:

  • 1-VISION.md:BestBlogs 为什么存在,以及长期方向
  • 2-PRODUCT.md:BestBlogs 的产品结构、能力边界和阶段演进
  • 3-BRAND.md:BestBlogs 的品牌表达、语气和体验边界

BestBlogs 是 AI 驱动的私人阅读助手,帮助用户建立稳定、可信、个性化的高质量信息输入。

架构文档回答的问题是:为了长期支撑这个产品定位,系统应该如何分层,核心领域边界如何定义,关键链路如何流动,运行时如何组织,以及哪些演进条件出现时才应该引入新的复杂度。


0. 文档定位

本文档描述 BestBlogs 当前生效的系统架构、核心边界、关键链路与演进约束。

它不是历史方案归档,不是 Issue changelog,不是部署手册,也不是具体功能 spec。它关注的是长期稳定的架构原则和系统边界,帮助团队在新增功能、重构链路、扩展端侧能力、开放 API 或引入新中间件时,判断应该如何放置能力、如何守住边界、如何避免系统随功能增长而失去一致性。

本文档默认遵循以下规则:

  1. 记录当前生效或已经明确采纳的架构方案
    不把尚未验证的未来想象写成当前现实。

  2. 关注长期边界,不记录实施流水账
    Issue 编号、具体 cron、Feature Flag 名称、错误码、线程池参数、Controller 细节、告警 dedupKey 等内容,应下沉到 specs、runbooks、operations 或代码事实中。

  3. 以产品结构为锚,以代码事实为准
    本文档服务于 VISION / PRODUCT / BRAND,但当文档描述与真实代码发生冲突时,以当前代码和已执行决策为准,并及时修正文档。

  4. 架构优先保持简单、清晰、可演进
    当前阶段优先通过清楚的领域边界、统一治理和适度自动化支撑单人团队效率,不为了形式上的完整性过早引入复杂运行单元。


1. 架构目标

BestBlogs 的架构不是为了接入更多来源、堆叠更多 AI 能力,也不是为了追求形式上的平台化。

它服务于一个核心目标:

稳定地把高质量内容转化为可信的公共判断,再转化为每个用户真正适合自己的阅读流。

围绕这个目标,BestBlogs 架构需要同时支撑以下五件事。

1.1 形成稳定的公共质量判断

BestBlogs 首先需要把分散在不同平台、语言和媒介中的内容,转化为公共可见、可复用、可信赖的高质量内容资产。

这要求系统具备:

  • 多来源内容采集能力;
  • 内容预处理、过滤、分析、翻译和审核能力;
  • 公共可见性边界;
  • 稳定的质量判断流程;
  • 可被公共入口复用的内容结构。

公共质量判断是 BestBlogs 的信任基础。没有公共质量池,我的早报、内容广场、主题解读、OpenAPI 和后续 Agent-friendly 能力都会失去共同底座。

1.2 形成个人化阅读流

BestBlogs 不只是公共精选内容入口,还需要把公共判断力和用户自己的关注、兴趣、阅读行为结合起来,形成真正属于用户的个人阅读流。

这要求系统具备:

  • 用户关注来源、主题和方向的能力;
  • 兴趣标签与行为学习能力;
  • 我的早报生成能力;
  • 我的关注和我的阅读承接能力;
  • 我的回顾形成日终闭环;
  • 可解释的推荐与排序能力。

个人化阅读流的原则是:

用户先选择来源,AI 再帮助筛选。

个性化不能变成黑盒投喂,也不能绕过用户主动选择和公共质量边界。

1.3 提供跨语言和跨媒介理解能力

BestBlogs 的重要价值之一,是让不同语言、不同媒介的一手内容进入用户的阅读流。

系统需要支持:

  • 文章、播客、视频、推文等不同媒介;
  • 中文、英文及更多语言的一手内容;
  • 摘要、翻译、解释、提问、章节跳转和 AI 伴读;
  • 原文与译文之间的可理解关系;
  • 长内容、转录文本和跨文章上下文的处理。

跨语言能力不是简单的翻译按钮,而是一手内容进入路径。它让用户减少对二手转述的依赖,直接理解原始信息和重要观点。

1.4 保持用户控制权和可解释性

BestBlogs 的个性化必须可理解、可回溯、可调节。

系统需要保证:

  • 用户可以主动关注和取消关注来源;
  • 用户可以表达不感兴趣等负反馈;
  • 推荐结果尽量能说明来源、匹配原因和个性化依据;
  • 行为学习来自阅读、收藏、划线、关注等自然行为;
  • 不开放复杂的手动调权配置;
  • 不通过黑盒推荐替用户决定信息边界。

架构上需要避免推荐、画像、配额、门禁等规则散落在多个入口中,导致同一行为在不同端表现不一致。

1.5 开放稳定能力,但不破坏边界

长期看,BestBlogs 的质量判断、主题理解和结构化内容能力,可以通过 RSS、OpenAPI、CLI 和 Agent-friendly 接口开放给外部工具和智能体调用。

但开放调用层不是通用智能体入口,也不是内部能力的无差别暴露。

系统需要保证:

  • 先开放稳定原语,再开放组合能力;
  • 默认只暴露公共可见内容和明确授权内容;
  • 不泄露用户隐私上下文;
  • 不直接暴露内部推荐决策过程;
  • 开放接口有独立鉴权、配额、限流和审计边界;
  • 外部调用不影响面向人的核心阅读体验。

2. 总体架构

BestBlogs 架构由五层组成:

  1. 内容与质量层
  2. 个人阅读层
  3. AI 协助层
  4. 开放调用层
  5. 运行支撑层

这五层不是彼此孤立的系统,而是围绕「公共质量判断 → 个人阅读流 → 理解与沉淀 → 稳定开放」形成的一套能力组织方式。

外部内容来源
  ↓
内容与质量层
  ↓
公共质量池
  ↓
公共策展层 ───────────────→ 开放调用层
  ↓
个人阅读层
  ↓
AI 协助层
  ↓
我的早报 / 我的关注 / 我的阅读 / 我的回顾

2.1 内容与质量层

内容与质量层负责把外部内容转化为可消费、可筛选、可推荐、可公开或可授权访问的内容资产。

它承担:

  • 来源接入;
  • 内容抓取与导入;
  • 预处理与清洗;
  • 低质量过滤;
  • AI 分析与结构化;
  • 翻译与语言处理;
  • 审核与人工校准;
  • 内容状态机与可见性边界;
  • 公共质量池形成。

这一层的核心问题是:

什么内容值得进入 BestBlogs 的内容体系,以及它可以在哪些场景被消费?

2.2 个人阅读层

个人阅读层负责把公共质量池和用户主动选择的来源、主题、兴趣、行为结合起来,形成个人阅读流。

2.2.1 临时特刊域

世界杯特刊通过独立 worldcup 域承接赛事、预测、虚拟金球币、竞猜、榜单和普神公开单。它复用现有用户、Pro、来源、内容与参数体系,但使用独立 Mongo collections、独立领域服务、独立公开 API 与管理 API,避免把一期活动玩法扩散进 Daily Brief、Explore、Topic 或我的空间核心链路。

该域不新增运行时服务单元,仍落在现有 bestblogs-common / bestblogs-api / bestblogs-admin-api / bestblogs-worker / bestblogs-app 内。所有公开能力默认由 Feature Flag 关闭,生产公开页必须在 FEATURE_WORLDCUP_SPECIAL_ENABLED && WORLDCUP_COMPLIANCE_APPROVED && WORLDCUP_PUBLIC_PAGE_ENABLED 同时开启后才可访问;竞猜写路径必须同时满足总开关、合规批准和 WORLDCUP_BETTING_ENABLED

它承担:

  • 我的早报;
  • 我的关注;
  • 我的阅读;
  • 我的回顾;
  • 用户关注与取消关注;
  • 兴趣标签与 Domain 配比;
  • 行为学习;
  • 来源偏好;
  • 推荐解释;
  • Free / Pro 工作流边界。

这一层的核心问题是:

对这个具体用户来说,今天什么内容真正值得读?

2.3 AI 协助层

AI 协助层负责降低用户理解内容的成本,但不替代用户阅读和判断。

它承担:

  • 摘要;
  • 翻译;
  • 术语解释;
  • 提问;
  • 章节跳转;
  • 内容对照;
  • 长音视频理解;
  • 跨文章上下文;
  • 主题关联。

这一层的核心问题是:

如何帮助用户更快进入内容、更好理解内容,并保留自己的判断?

AI 协助层横跨公共策展层和我的空间,但权限、配额、内容可见性必须由服务层统一治理。

2.4 开放调用层

开放调用层负责把 BestBlogs 已经稳定的内容、质量判断和结构化能力,以受控方式开放给外部工具、个人脚本、RSS 阅读器、CLI 和智能体。

它承担:

  • RSS;
  • OpenAPI;
  • CLI;
  • Agent-friendly 接口;
  • API Key;
  • 外部调用限流;
  • 开放接口配额;
  • 公共内容与授权内容的调用边界。

这一层的核心问题是:

哪些能力已经足够稳定,可以被外部调用,并且不会破坏用户隐私和产品边界?

开放调用层是私人阅读助手能力的延伸,不是新的主产品定义。

2.5 运行支撑层

运行支撑层负责系统运行所需的基础能力。

它承担:

  • 主存储;
  • 搜索读模型;
  • 缓存;
  • 分布式锁;
  • 任务调度;
  • 配置与 Feature Flag;
  • 鉴权与权限;
  • 配额与限流;
  • 可观测性;
  • 告警与降级;
  • 部署拓扑。

这一层的核心问题是:

如何用足够简单、可维护、可演进的技术结构,支撑前四层稳定运行?


3. 核心领域边界

架构文档最重要的职责是定义边界。边界清楚,系统才不会随着功能增长而变形。

3.1 公共内容与私有内容边界

BestBlogs 必须清楚区分公共内容和私有内容。

公共内容可以进入:

  • 每日早报;
  • 精选周刊;
  • 主题解读;
  • 内容广场;
  • 公共搜索;
  • RSS;
  • OpenAPI 公共接口;
  • 公共分享与 SEO 页面。

私有内容只能进入明确授权用户的个人阅读流,例如:

  • 我的关注;
  • 我的早报;
  • 我的阅读;
  • 我的回顾;
  • 用户自己的搜索、阅读和 AI 协助场景。

硬约束:

  1. 公共入口只能消费公共可见内容。
  2. 私有来源内容不得进入公共早报、内容广场、公共搜索、公共推荐和公共 OpenAPI。
  3. 用户添加的来源可以服务个人化阅读流,但不能自动成为公共内容。
  4. 社区源可以在满足条件时复用源元数据,但不等于内容公开。
  5. 可见性字段可以在内容侧做必要冗余,但业务语义必须有统一来源。
  6. 开放接口默认只暴露公共可见内容和明确授权内容。

这条边界是 BestBlogs 信任体系的一部分。任何架构调整都不能让私有内容污染公共层。

3.2 公共质量池边界

公共质量池是 BestBlogs 的核心内容资产。

进入公共质量池的内容,需要经过基本的内容处理和质量判断链路。未完成处理、未通过质量判断、未满足公开条件的内容,不得进入公共消费入口。

硬约束:

  1. 内容状态机不仅是任务推进机制,也是公共质量边界。
  2. 未完成状态不得进入每日早报、内容广场、公共搜索、主题解读和开放接口结果。
  3. 公共入口默认只消费完成处理且可公开的内容。
  4. 低质量内容应尽量在早期过滤,避免浪费后续 AI 分析和人工校准成本。
  5. AI 初筛提供规模,人工校准定义品味、边界和质量标准。

公共质量池的目标不是「收录更多」,而是持续形成可信、可复用、可解释的高质量内容资产。

3.3 用户选择与个性化边界

BestBlogs 的个性化建立在用户主动选择之上。

用户先选择自己愿意长期关注的来源、主题和方向,系统再在这些范围内帮助筛选、排序、解释和关联。

硬约束:

  1. 关注体系是用户主导的信息输入端。
  2. 系统可以提供候选建议,但是否关注始终由用户主动确认。
  3. 个性化排序应尽量提供推荐解释。
  4. 推荐不能绕过公共质量判断和内容可见性边界。
  5. 不开放用户手动调权配置。
  6. 兴趣权重由关注、阅读、收藏、划线、反馈等行为学习产生。
  7. 用户取消关注或表达不感兴趣后,系统应尊重该信号。

个性化的目标不是让用户沉迷,而是帮助用户更快找到真正适合自己的内容。

3.4 AI 能力边界

AI 在 BestBlogs 中承担规模化初筛、结构化分析、跨语言理解和阅读协助职责。

AI 可以做:

  • 内容过滤;
  • 摘要;
  • 翻译;
  • 单层 domain 分类识别(8 个一级领域,不再有二级子分类);
  • 六维兴趣标签识别(承担细粒度分类职责);
  • 质量评分辅助;
  • 术语解释;
  • 提问;
  • 章节跳转;
  • 内容关联;
  • 跨文章上下文辅助。

AI 不应该做:

  • 替用户完成最终判断;
  • 替用户决定信息边界;
  • 绕过内容可见性;
  • 绕过 Pro 权限;
  • 生成无法追溯来源的公共事实断言;
  • 将私人上下文暴露给公共入口或开放接口。

AI 相关能力必须接受权限、配额、可见性和成本治理。

3.5 Free / Pro 能力边界

Free 和 Pro 的区别不是简单功能数量差异,而是产品价值层级差异。

架构上必须保证:

  1. Pro Only 能力由服务层集中守门。
  2. 前端不得作为权限判断真相。
  3. Controller 不应散落重复门禁逻辑。
  4. 配额、权限和可见性应在领域服务层统一治理。
  5. 配额应使用用户可感知的动作次数表达,不暴露 token、字符数等内部计量。
  6. Pro 状态应有单一可信来源,跨端能力以服务端判断为准。
  7. 触达、邮件、移动端、Web 不应各自实现互相冲突的 Pro 边界。

典型 Pro Only 能力包括:

  • 个性化每日早报;
  • 我的早报邮件触达;
  • 跨文章 AI 伴读;
  • 长视频 / 长播客深度伴读;
  • 自定义视图;
  • 我的回顾;
  • 按 Domain 自定义早报篇数。

具体产品边界以 2-PRODUCT.md 为准,架构负责保证这些边界在实现层不漂移。

3.6 开放调用边界

开放调用层只开放稳定、受控、可配额治理的能力。

硬约束:

  1. 默认不暴露私有内容。
  2. 默认不暴露用户隐私上下文。
  3. 默认不暴露内部推荐决策过程。
  4. 默认不暴露后台审核流程和内部任务状态。
  5. OpenAPI / RSS / CLI / Agent-friendly 接口必须有清晰的鉴权、限流和配额边界。
  6. 对外契约需要保持版本兼容和下线策略。
  7. Agent-friendly 能力是被调用,不是让 BestBlogs 变成通用智能体调度平台。

开放调用层必须建立在公共质量池、可见性边界和内容结构稳定之后。


4. 核心链路

本章描述 BestBlogs 的关键主链路。具体 Job、Controller、Feature Flag、参数、错误码和运维细节由对应 spec 与 runbook 承接。

4.1 内容进入与质量判断链路

外部来源
  → 抓取 / 导入
  → 预处理
  → 过滤
  → 分析
  → 翻译
  → 审核 / 校准
  → 公共质量池 / 私人来源池

这条链路负责把原始内容转化为 BestBlogs 可消费的内容资产。

架构责任:

  • 保证来源进入路径可扩展;
  • 保证低质量内容尽量在早期被过滤;
  • 保证内容状态机可追踪;
  • 保证处理失败可重试或可降级;
  • 保证公共内容与私有内容在可见性上不混淆;
  • 保证 AI 初筛和人工校准有清晰分工;
  • 保证处理完成前不进入公共消费入口。

4.2 公共策展链路

公共质量池
  → 每日早报
  → 精选周刊
  → 主题解读
  → 内容广场
  → RSS / OpenAPI

公共策展链路负责把公共质量池转化为所有访问者都能感知的判断力。

架构责任:

  • 保证公共入口共用一致的质量边界;
  • 保证每日早报、精选周刊、主题解读和内容广场从同一公共质量体系中取数;
  • 保证内容广场保持公共一致性,不引入黑盒个性化默认排序;
  • 保证每日早报、精选周刊、主题解读等匿名公共页面可访问,但不产生未授权的个人数据副作用;
  • 保证公共入口适合作为 SEO、分享和品牌信任入口。

注(#908 后续产品决策):非登录用户不支持查看「内容广场」。landing 首页 / footer / 顶部导航 / 侧边栏 / 移动二级导航 / 404 与错误页等默认入口均收敛到「每日早报 / 精选周刊 / 主题解读」三个公共策展入口;/explore 仅登录后可查看,未登录访问时引导登录。

4.3 个人阅读链路

公共质量池
  + 用户关注来源
  + 兴趣画像
  + 阅读行为
  → 我的早报
  → 我的关注
  → 我的阅读
  → 我的回顾

个人阅读链路负责把公共判断力和用户主动选择结合起来,形成稳定的个人阅读节奏。

架构责任:

  • 保证我的早报是 Pro 价值兑现的核心入口;
  • 保证关注体系是用户主导的信息输入端;
  • 保证我的阅读承接阅读理解、收藏、划线、历史和笔记;
  • 保证我的回顾形成日终阅读闭环;
  • 保证推荐排序能使用关注、兴趣和行为数据,但不破坏可解释性;
  • 保证用户私有来源只进入授权用户的个人阅读流;
  • 保证行为学习数据可用于个性化,但不成为黑盒不可控系统。

4.4 AI 协助链路

内容详情 / 原文内容 / 转录文本 / 用户阅读上下文
  → 摘要
  → 翻译
  → 解释
  → 提问
  → 章节跳转
  → 跨文章关联

AI 协助链路负责降低理解成本。

架构责任:

  • 保证 AI 协助依附于具体阅读场景;
  • 保证翻译、摘要、解释和问答可追溯到原始内容;
  • 保证长音视频和跨文章能力遵守 Pro 边界;
  • 保证 AI 调用有配额、成本和降级治理;
  • 保证 AI 失败时不破坏基础阅读体验;
  • 保证 AI 输出不替代原文和用户判断。

4.5 触达链路

我的早报 / 我的回顾 / 产品通知
  → 邮件
  → Web
  → Mobile Push
  → 其他可用通路

触达链路负责让 BestBlogs 的价值稳定到达用户。

架构责任:

  • 保证我的早报和我的回顾可以通过可靠通路触达;
  • 保证邮件、Web、Mobile Push 的触达状态可观测(per-recipient 投递日志统一走 bb_message_delivery_log,支持 per-recipient 失败重试与 webhook 回写);
  • 保证触达不变成骚扰式增长;
  • 保证用户可以退订、关闭或调整触达;
  • 保证触达通路失效时有备选路径和降级方案(多 Provider 邮件路由:Sendflare 默认 + Resend 兜底);
  • 保证不同触达通路不会产生重复、冲突或错误的 Pro 权益判断。

4.6 开放调用链路

公共质量池 + 稳定内容原语
  → RSS
  → OpenAPI
  → CLI
  → Agent-friendly 接口

开放调用链路负责把 BestBlogs 的稳定能力提供给外部工具和智能体。

架构责任:

  • 先开放稳定原语,再开放组合能力;
  • 公共内容和用户授权内容分开治理;
  • 对外接口具备版本、鉴权、配额、限流和观测;
  • 不泄露内部推荐决策和用户隐私上下文;
  • 外部调用能力不优先于面向人的核心阅读体验。

5. 运行时边界

5.1 仓库与运行单元

BestBlogs 当前采用 monorepo 结构,以保证领域模型、仓储、配置体系、共享能力和前后端协作的一致性。

bestblogs-monorepo/
├── bestblogs-app            # 用户 Web 端
├── bestblogs-admin          # 管理端 Web
├── bestblogs-mobile         # 移动端 App
├── bestblogs-service
│   ├── bestblogs-api        # 用户 API
│   ├── bestblogs-admin-api  # 管理 API + Job 宿主
│   ├── bestblogs-worker     # 任务领域库,当前不独立部署
│   └── bestblogs-common     # 共享领域、仓储、适配器、配置与公共能力
└── deploy                   # 部署与环境模板

各运行单元职责如下。

5.2 bestblogs-app

bestblogs-app 是用户 Web 端,承载公共策展层和我的空间的主要 Web 体验。

职责:

  • 首页、About、Pricing 等公开页面;
  • 每日早报、精选周刊、主题解读、内容广场;
  • 我的早报、我的关注、我的阅读、我的回顾;
  • 内容详情页;
  • AI 伴读与沉浸式翻译的 Web 入口;
  • 登录、Pro 引导、用户设置等体验。

边界:

  • 前端负责展示、交互、路由和轻量适配;
  • 不作为权限、配额、Pro 状态和内容可见性的最终判断来源;
  • 与权限、配额、门禁相关的业务真相应由服务端提供;
  • 公共页面可以匿名访问,但个人行为副作用必须在登录态下发生。

5.3 bestblogs-admin

bestblogs-admin 是管理端,承载内容审核、运营配置、系统管理、指标看板和后台任务管理。

职责:

  • 内容审核与校准;
  • 来源管理;
  • 配置与 Feature Flag 管理;
  • Pro 管理;
  • 邮件与运营任务;
  • 指标看板;
  • 管理员权限和审计。

边界:

  • 管理端不应绕过核心领域服务直接破坏用户侧语义;
  • 高风险操作需要权限分层和审计;
  • 管理端配置影响用户体验时,应有明确灰度和回滚路径。

5.4 bestblogs-mobile

bestblogs-mobile 是移动端 App,承载移动阅读、早报触达、内容浏览、AI 伴读和推送。

职责:

  • 移动端早报;
  • 内容广场;
  • Reader;
  • 我的关注;
  • AI 伴读;
  • 推送触达;
  • 移动端 Pro 识别与订阅状态展示。

边界:

  • Mobile 可以有独立 API 命名空间和鉴权链路;
  • Mobile 不复制业务真相;
  • 跨端 Pro 状态以服务端用户状态为准;
  • 移动端设计 token、可达性和多语言能力应与品牌和设计系统保持一致。

5.5 bestblogs-api

bestblogs-api 是用户侧 API,承载 Web 和 Mobile 的用户请求、内容查询、个人阅读、AI 协助、推荐、Pro 状态和开放接口的部分能力。

职责:

  • 用户鉴权;
  • 内容查询;
  • 我的早报查询;
  • 我的关注;
  • 我的阅读;
  • 我的回顾;
  • AI 伴读;
  • 翻译;
  • Pro 状态与配额;
  • OpenAPI 鉴权与调用;
  • 公开内容读取。

边界:

  • 用户侧业务规则应尽量收敛在领域服务;
  • API 层不应复制复杂权限规则;
  • Web、Mobile、OpenAPI、RSS 等不同调用方必须有清晰信任边界;
  • 私有内容、用户上下文和 Pro 能力必须受服务层治理。

5.6 bestblogs-admin-api

bestblogs-admin-api 是管理 API 和后台任务宿主。

职责:

  • 管理端 API;
  • 后台 Job 调度;
  • 内容生产与分发任务;
  • 邮件发送任务;
  • 指标聚合;
  • 审核与维护任务;
  • 系统管理操作。

边界:

  • 后台任务需要分布式锁和幂等保障;
  • 多实例部署时不得重复执行同一全局任务;
  • 任务失败需要可观测、可重试、可降级;
  • 管理 API 和任务宿主当前共进程,只有在明确触发条件出现时才拆分。

5.7 bestblogs-worker

bestblogs-worker 当前保持为任务领域库,由 bestblogs-admin-api 依赖,不独立部署。

职责:

  • 后台任务领域逻辑;
  • 任务定义;
  • 执行辅助能力;
  • 与内容生产、早报生成、邮件分发、推送等任务相关的共享能力。

边界:

  • 不独立暴露端口;
  • 不单独扩容;
  • 不形成新的部署单元;
  • 当前阶段优先减少部署复杂度和运维成本。

5.8 bestblogs-common

bestblogs-common 承载跨模块共享的领域模型、仓储接口、适配器、配置键和公共能力,是系统一致性的基础层。

职责:

  • 领域模型;
  • 仓储接口;
  • 枚举和状态机;
  • 配置键;
  • 外部服务适配器;
  • 通用工具;
  • 跨 api / admin-api / worker 的共享能力。

边界:

  • 不应依赖上层具体 API 模块;
  • 不放置只属于某个端的控制器或展示逻辑;
  • 共享领域能力需要保持稳定,不被单一功能的临时实现污染。

5.9 API 信任边界

BestBlogs 存在多种 API 调用方,不同调用方信任边界不同,不能只按路径前缀粗暴复用同一鉴权假设。

主要 API 类型:

类型 调用方 边界
Web 用户 API bestblogs-app 代理层 受内部 token、用户 JWT、权限和配额治理
Mobile API bestblogs-mobile 直连 独立移动端鉴权语义,服务端校验 token 与用户状态
Admin API bestblogs-admin 管理员鉴权、角色分层、操作审计
OpenAPI 外部开发者 / 工具 / Agent API Key、限流、每日配额、版本边界
RSS RSS 阅读器 / 播客客户端 公共读取或 token 化个人 feed,需限流与防滥用
第三方回调 支付、OAuth、Webhook 等 依赖签名、state、token 或专门校验机制
邮件公开端点 邮件客户端 / 用户浏览器 退订、打开、点击等入口需要 token、防枚举和限流
内部系统回调 监控、告警、运维系统 内部 token、限流豁免和告警去重

新增 API 时必须先判断所属信任边界,再决定鉴权、限流、配额、可见性和审计策略。

5.10 前后端职责边界

前端和后端应遵守以下职责边界:

  1. 业务真相在服务端。
  2. 前端负责体验,不负责最终权限判断。
  3. Pro 状态、配额、可见性、私有内容访问、公开内容访问都以服务端判断为准。
  4. 前端可以做乐观 UI 和轻量 gating,但不能替代服务端门禁。
  5. Web 与 Mobile 可以有不同体验,但应共享同一产品语义。
  6. 端侧不复制复杂业务规则,避免多端漂移。

6. 数据与中间件架构

6.1 当前技术基线

BestBlogs 当前技术基线:

  • Java 21
  • Spring Boot 3.x
  • MongoDB
  • Elasticsearch
  • Redis
  • Next.js App Router
  • React
  • React Native + Expo
  • 本地缓存
  • 无独立消息队列
  • monorepo 结构

本文档不追求列出所有版本细节,具体版本和配置以代码仓库与部署文件为准。

6.2 MongoDB

MongoDB 是 BestBlogs 的主存储和核心业务真相来源。

承载:

  • 用户;
  • 内容资源;
  • 来源;
  • 关注关系;
  • 阅读行为;
  • 早报;
  • 回顾;
  • Pro 状态;
  • 配额与日志;
  • 管理审计;
  • 任务记录;
  • 配置快照。

原则:

  1. MongoDB 存储业务真相。
  2. Redis 不替代 MongoDB 的长期状态。
  3. Elasticsearch 不作为业务真相来源。
  4. 关键状态变更需要幂等和可追溯。
  5. 与用户权益、内容可见性、付费状态相关的数据,需要有明确的单一语义来源。

6.3 Elasticsearch

Elasticsearch 是搜索读模型和检索增强基础设施。

承载:

  • 全文搜索;
  • 多字段检索;
  • 标签检索;
  • 相似内容;
  • 向量召回;
  • 语义搜索扩展。

原则:

  1. ES 是读模型,不是业务真相。
  2. 搜索索引可以重建,业务状态不能只存在 ES。
  3. MongoDB 到 ES 的同步需要可观测和可修复。
  4. 向量召回是推荐和搜索增强能力,应能通过开关降级到基础检索。
  5. 搜索能力不得绕过内容可见性边界。

6.4 Redis

Redis 是共享缓存、分布式协调、限流和短期共享状态支撑。

引入 Redis 的原因不是追求形式上的现代化,而是解决多实例部署下的现实问题:

  • 本地缓存无法跨节点共享;
  • 分布式任务需要互斥;
  • 限流和配额需要共享计数;
  • 短期状态需要低延迟读写;
  • 多实例环境需要统一失效能力。

Redis 适合承载:

  • L2 共享缓存;
  • API Key 元数据缓存;
  • 配置缓存;
  • 分布式锁;
  • 限流计数;
  • 短期幂等标记;
  • 短 TTL 中间状态;
  • 任务协调状态。

Redis 不适合承载:

  • 长期业务真相;
  • 用户权益唯一来源;
  • 内容主数据;
  • 需要长期审计的业务日志;
  • 搜索排序和复杂检索。

Redis 不可用时,关键链路应尽量有降级策略,但分布式锁、限流和部分共享状态能力可能需要进入保守模式。

6.5 本地缓存

本地缓存用于节点内热点数据和低延迟读取。

原则:

  1. 本地缓存只承担节点内优化。
  2. 跨节点共享状态不得只依赖本地缓存。
  3. 本地缓存失效策略需要与 Redis 或数据源保持一致。
  4. 本地缓存不可作为权限、配额、Pro 状态等关键判断的唯一依据。

6.6 为什么暂不引入消息队列

当前 BestBlogs 暂不引入 Kafka、RabbitMQ 等独立消息队列。

原因:

  1. 当前异步任务主要由 Job、数据库状态、分布式锁和幂等机制支撑。
  2. 高吞吐事件流尚未成为主要瓶颈。
  3. 多消费者异步解耦需求还没有强到覆盖额外运维成本。
  4. 当前阶段更重要的是收敛链路和保持边界清晰,而不是增加新的运行单元。
  5. 单人团队需要控制中间件复杂度。

出现以下条件时,再重新评估消息队列:

  • 高吞吐事件流成为常态;
  • 多消费者异步解耦需求显著增加;
  • 跨系统可靠投递成为关键诉求;
  • 当前 Job + DB 状态机模式无法支撑任务峰值;
  • 引入消息队列能明显降低而不是增加整体复杂度。

6.7 为什么 worker 暂不独立部署

bestblogs-worker 当前不独立部署,继续作为库模块由 bestblogs-admin-api 承载任务运行。

原因:

  1. 当前任务规模尚未要求单独扩容。
  2. 独立部署会增加配置、发布、观测和故障处理成本。
  3. 单人团队需要减少运行单元。
  4. 当前更重要的是任务幂等、锁语义、可观测和降级,而不是进程拆分。

出现以下条件时,再评估拆分 worker:

  • 后台任务资源消耗明显影响管理 API 稳定性;
  • 后台任务需要与管理 API 独立扩缩容;
  • 后台任务需要独立发布节奏;
  • 任务失败需要和管理能力做更强隔离;
  • 独立 worker 能显著简化而不是复杂化任务治理。

7. 横切治理

横切治理负责让分散在不同入口的能力遵循统一规则。

7.1 配置与 Feature Flag

BestBlogs 的关键能力应通过统一配置体系治理。

原则:

  1. 开关和配置需要有清晰业务语义。
  2. 避免在业务代码中散落魔法字符串。
  3. 高风险能力应支持灰度、回滚和 kill switch。
  4. 动态配置变更后需要触发缓存刷新或失效。
  5. 配置只解决运行时策略,不替代产品边界。
  6. 临时开关不应长期沉淀为系统复杂度。

7.2 权限与门禁

权限与门禁必须收敛到服务层和领域服务。

原则:

  1. Pro Only 能力服务层集中守门。
  2. 管理权限需要角色分层和审计。
  3. OpenAPI 通过 API Key 和配额治理。
  4. RSS 公开读取与个人 token feed 区分。
  5. Mobile、Web、Admin、OpenAPI 信任边界不能混用。
  6. 前端只做体验 gating,不做最终授权判断。

7.3 配额与限流

配额和限流的目标是保护系统成本、外部依赖和用户体验。

原则:

  1. 用户可感知的能力用动作次数表达。
  2. 内部成本可以按 token、字符数、调用次数计量,但不暴露给用户。
  3. AI 能力需要配额、成本和降级治理。
  4. OpenAPI 需要独立速率限制和每日配额。
  5. 公开匿名接口需要防刷保护。
  6. 配额超限要有清晰反馈,不应表现为随机失败。

7.4 缓存与失效

缓存用于提升性能,不改变业务真相。

原则:

  1. MongoDB 是业务真相。
  2. Redis 是共享缓存和短期状态。
  3. 本地缓存是节点内优化。
  4. 缓存失效要封装统一语义。
  5. 关键权限、Pro 状态、内容可见性不能只依赖本地缓存。
  6. 缓存不可用时,系统应尽可能降级到数据源或保守模式。

7.5 分布式锁与任务幂等

BestBlogs 的后台任务需要在多实例环境下安全运行。

原则:

  1. 跨节点互斥不得依赖 JVM 本地锁。
  2. 全局任务需要分布式锁。
  3. 用户级或资源级任务需要幂等键。
  4. 外部回调与后台轮询之间需要明确进程边界。
  5. 任务失败应可重试。
  6. 重试不得导致重复发放权益、重复发送高风险消息或重复生成不可合并数据。
  7. 任务状态、失败原因和执行结果需要可观测。

7.6 搜索与向量召回

搜索和向量召回是内容发现、相似推荐和个性化的增强能力。

原则:

  1. 标签召回和向量召回可以并行,但必须受可见性边界约束。
  2. 向量召回关闭时,基础搜索和标签召回应保持可用。
  3. 召回结果需要进入统一重排或过滤,不直接绕过质量判断。
  4. 用户兴趣向量来自行为学习,不来自用户手动调权。
  5. ES 索引可以重建,业务真相不能只存 ES。

7.7 可观测性与降级

关键链路需要可观测、可告警、可降级。

优先覆盖:

  • 内容生产链路;
  • 公共早报;
  • 我的早报;
  • AI 伴读;
  • 沉浸式翻译;
  • OpenAPI;
  • 邮件与推送;
  • Pro 权益;
  • 后台任务;
  • 分布式锁;
  • 外部服务调用。

降级原则:

  1. 推荐超时可以降级到更简单召回。
  2. AI 服务异常不应破坏基础阅读。
  3. 邮件发送失败应可重试或走备用 Provider。
  4. 外部支付或权益同步失败不应吞掉用户已获得权益。
  5. OpenAPI 过载时应快速失败并给出明确错误。
  6. 公共入口异常时优先保持可读,不展示未审核内容。

7.8 数据隐私与内容可见性

内容可见性和用户隐私是架构红线。

原则:

  1. 私有内容不得进入公共入口。
  2. 用户行为数据只用于明确的个性化和产品分析目的。
  3. 推荐解释可以说明匹配原因,但不暴露敏感内部数据。
  4. 开放接口默认不带用户隐私上下文。
  5. 日志、埋点和告警不得记录敏感 token、完整私有 URL、支付密钥或第三方凭证。
  6. 邮件、RSS、Magic Link 等公开入口必须防止 token 泄露和暴力枚举。

8. 架构风险与演进触发条件

架构风险不是单纯列问题,而是帮助系统在复杂度上升前识别需要调整的信号。

8.1 当前主要风险

风险 说明
内容质量链路被绕开 推荐或开放接口绕过公共质量池,损害品牌信任
私有内容污染公共入口 用户私有来源内容进入公共早报、内容广场或公共 API
个性化黑盒化 用户不知道为什么看到某内容,也无法通过行为调整
Pro 门禁散落 前端、Controller、服务层各自判断,导致权益不一致
AI 成本和外部服务波动 AI 服务超时、质量下降或成本上升影响核心体验
我的早报生成窗口超时 Pro 用户规模扩大后,早报生成无法在承诺时间内完成
触达通路退化 邮件打开率下降,Push 或其他通路未能补位
OpenAPI 滥用 开放接口被刷、被爬或超出成本预期
Job 多实例竞争 重复执行导致重复发送、重复发放权益或状态撕裂
单人维护复杂度上升 中间件、任务、配置、入口过多,超过可持续维护能力

8.2 引入消息队列的触发条件

只有当以下信号明显出现时,才重新评估消息队列:

  1. Job + DB 状态机模式无法支撑任务峰值;
  2. 同一事件需要被多个消费者可靠处理;
  3. 跨系统可靠投递成为关键业务要求;
  4. 当前轮询和任务机制导致明显延迟或重复复杂度;
  5. 消息队列能减少系统复杂度,而不是增加运维负担。

8.3 worker 独立部署触发条件

只有当以下信号明显出现时,才评估将 bestblogs-worker 独立部署:

  1. 后台任务影响管理 API 稳定性;
  2. 后台任务需要独立扩缩容;
  3. 任务执行资源和管理 API 资源需要隔离;
  4. 任务发布节奏与管理 API 明显不同;
  5. 独立 worker 能显著降低任务治理复杂度。

8.4 Redis 使用边界变化触发条件

Redis 已经是当前生效架构的一部分,但其使用范围仍需受控。

需要重新评估 Redis 使用边界的情况:

  1. Redis 承载了过多长期业务状态;
  2. Redis 不可用导致关键业务不可恢复;
  3. 分布式锁与任务协调开始依赖复杂脚本且难以维护;
  4. 限流、配额和缓存语义出现混乱;
  5. 跨节点一致性要求超过 Redis 当前设计能力。

8.5 OpenAPI / Agent-friendly 能力扩张触发条件

开放调用能力扩张需要满足以下条件:

  1. 公共质量池结构足够稳定;
  2. 内容可见性边界足够稳定;
  3. 权限、配额、限流和审计机制足够稳定;
  4. 外部调用需求真实存在;
  5. 不影响我的早报、我的阅读等面向人的核心体验;
  6. 不暴露用户隐私上下文;
  7. 不把 BestBlogs 变成通用智能体入口。

8.6 Mobile 能力扩张触发条件

Mobile 是私人阅读助手的重要触达端,但移动端扩张也应保持克制。

需要重点评估:

  1. Mobile 是否强化我的早报、我的阅读、我的回顾,而不是制造新的复杂入口;
  2. Push 是否提升价值触达,而不是变成骚扰;
  3. 移动端 Pro 状态是否与 Web 一致;
  4. 移动端是否复制了本应在服务端治理的业务规则;
  5. 多端 UI 差异是否仍保持统一产品语义。

9. 文档维护规则与事实锚点

9.1 什么时候必须更新本文档

当以下任一情况发生时,应更新本文档:

  1. 新中间件被正式引入或移除;
  2. 核心链路发生边界变化;
  3. 公共内容与私有内容可见性规则发生变化;
  4. Free / Pro 能力边界发生变化;
  5. OpenAPI / RSS / Agent-friendly 开放范围发生变化;
  6. 部署单元发生实质变化;
  7. 后台任务运行模式发生变化;
  8. API 信任边界发生变化;
  9. 配置、缓存、锁、限流、配额的统一治理方式发生变化;
  10. VISION / PRODUCT / BRAND 中的核心定位发生变化。

9.2 维护要求

  1. 先确认真实架构,再更新文档。
  2. 不把临时实现写成长期原则。
  3. 不把未来设想写成当前现实。
  4. 不在主文档展开 Issue 过程。
  5. 不在主文档维护具体 cron、Feature Flag、错误码、告警 key、线程池参数。
  6. 主文档优先解释「为什么这样组织」和「边界在哪里」。
  7. 具体实现交给 specs、runbooks、operations 和代码事实承接。

9.3 轻量事实锚点

以下事实锚点用于降低文档描述与代码实现漂移风险。这里只记录关键承接位,不展开实现细节。

架构事实 代码 / 文档锚点 说明
内容状态机 FlowStatusEnum 内容处理阶段和公共可见性边界
公共早报生成 GlobalBriefJob 公共策展层日入口生成
我的早报生成 UserBriefJob Pro 个性化早报生成(v2.4.0 起通过 AbstractDistributedJob 多节点分片执行,USER_BRIEF_DISTRIBUTED_ENABLED 切换)
Pro 即时早报 ProBriefBootstrapJob / ProBriefBootstrapService Pro 用户付费完成后 ≤ 15 min 内首份早报 SLA(v2.4.0)
邮件投递可观测 MessageDeliveryLogService / bb_message_delivery_log Brief / Daily Review / Newsletter 统一 per-recipient 状态机与重试锚点(v2.4.0)
内容多渠道发布 PublishTaskService / ApprovalTicket / TypefullyPublisher W1 多渠道发布基础设施 + Top10 HITL 审批(v2.4.0)
URL 一键发现订阅源 SourceDiscoveryRegistry + 各 SourcePlatformDiscoveryAdapter YouTube / 小宇宙 / 公众号 / 通用 HTML 兜底(v2.4.0)
内容可见性查询 ResourceQueryBuilder 公共 / 私有内容过滤边界
Pro 门禁 ProFeatureHelper Pro Only 能力集中守门
关注关系 SourceSubscriptionDomainService 用户关注、取消关注和来源关系
个人阅读沉淀 LibraryDomainService 收藏、划线、历史、笔记等阅读资产
沉浸式翻译 TranslationDomainService 用户触发的跨语言阅读能力
AI 伴读 Copilot 相关服务 阅读协助和问答能力
OpenAPI 鉴权 OpenApiAuthFilter 外部开放接口身份识别
OpenAPI 限流 OpenApiRateLimitFilter 外部开放接口速率控制
OpenAPI 配额 OpenApiDailyQuotaFilter 外部开放接口每日配额
分布式锁 @HoldJobLock / @DistributedLock Job 独占和跨节点互斥
配置体系 ConfigKey Feature Flag 与动态参数治理
搜索读模型 Elasticsearch 索引与同步服务 搜索、相似内容、向量召回
指标与观测 PostHog / JobExecutionLog / Actuator 产品指标、任务日志和系统健康