stable roots
让长期职责保持收敛
路由、契约、传输中间件以及面向存储的基础原语,应当保持足够清晰,才能长期守住兼容性。
判断 Plumego 最容易的方式,是先看清哪些职责留在内核、哪些能力向 x/* 扩展家族外分,以及默认请求路径从哪里开始、在什么地方结束。
stable roots
路由、契约、传输中间件以及面向存储的基础原语,应当保持足够清晰,才能长期守住兼容性。
extension rule
产品能力或协议适配应该从 x/* 家族开始,而不是不断吸入内核,最终让默认路径失去边界。
canonical path
网站、文档和 reference app 都应该先把从 bootstrap 到 write path 的默认路径讲清楚,再让读者进入更深的扩展区域。
每个 Plumego 服务处于三个模块层与机器可读控制面的交叉点。下图展示了完整结构、导入方向,以及 specs/ 如何规范允许哪些变更。
只有当内核、canonical 阅读路径与向外分叉的能力家族,能够带着真实仓库事实同时出现在一个视图里时,Plumego 才更容易被判断与信任。
可选协议与产品能力可以更快演进,但不应被吸收到内核里
每个新读者都先读同一条路径:bootstrap → wiring → route 注册 → 请求处理
长期兼容性表面,更慢、更窄,也更容易在评审里解释清楚
模块层次只是其中一条轨道。控制平面(specs/、docs/、tasks/)
在旁边并行运行,持有支配模块代码变更方式的机器可读规则。两条轨道都是一等公民,没有从属关系。
模块代码轨
控制平面轨
internal/checks/ 在 CI 阶段对模块代码执行 specs/ 中的规则。
人类和 AI 编码助手都不能绕过这个关卡。
如果一个新读者分不清某个改动属于稳定根、能力家族还是 canonical 应用路径,说明站点还没有把架构解释到位。
kernel
核心模块承担最强的兼容性负担,因此应保持收敛、克制,并且在代码评审时容易理解。
extensions
这些扩展很重要,但不应该假装与最小内核表面享受同一等级的稳定性承诺。
workflow
默认应用路径给团队提供统一 bootstrap 模型、统一路由流向,以及开始理解仓库的共同入口。
最快的架构阅读方式,是先从 reference app 入手,确认 app-local wiring,然后再向外展开到那些显然属于具体功能或协议的包。
先把入口保持克制,ownership 才会从显式代码开始。
bootstrap 是否自律,直接决定后续代码是否还容易读。
route 注册是第一张架构地图,而不是可以跳过的细节。
扩展应当建立在分类之后,而不是为了省事。
route 注册是服务的第一张架构地图。它应该能直接在评审里被读懂,而不是藏在框架源码或隐式注册里。
func (a *App) Routes() http.Handler {
r := router.New()
r.Use(middleware.RequestID())
r.Use(middleware.Logger(a.log))
r.Use(middleware.Recovery(a.log))
r.Get("/api/items", a.items.List)
r.Post("/api/items", a.items.Create)
r.Get("/health", health.Handler(a.checker))
// route map 保持可见,没有隐藏注册
return r
} type App struct {
log log.Logger
db *sql.DB
items *items.Handler
checker health.Checker
}
func New(cfg *config.Config, deps AppDeps) (*App, error) {
// 每个依赖都在构造函数里显式出现
return &App{
log: deps.Logger,
db: deps.DB,
items: items.NewHandler(deps.DB),
checker: health.NewChecker(),
}, nil
} 架构页不应该只把内核列出来,还应该说明哪些工作真的属于那里,以及哪些 root 名称本身就在提醒你:能力关注点正在继续向内漂移。
stable-root work intent
Change kernel, lifecycle, route structure, transport contracts, transport middleware, auth primitives, or storage primitives.
discouraged roots
这些名字在产品能力或协议语境里很常见,但它们不适合作为默认根,因为会模糊内核的 ownership 边界。
extension work intent
Change product capability, business feature, protocol adaptation, or extension behavior.
扩展家族不只是模块名——每个家族拥有一个具体的能力域。用下面五个场景判断哪个 x/* 家族最相关,再决定是否打开对应的模块手册。
multi-tenant saas
x/tenant 在 HTTP 内核之外提供强制租户身份、per-tenant 配额和策略评估。稳定根承担传输基线,x/tenant 承担租户层,两者互不污染。
打开 x/tenant 模块手册ai service
x/ai 在稳定 net/http 内核旁边提供 provider 抽象、session 生命周期和 streaming 响应处理。AI 能力工作留在默认请求路径之外。
打开 x/ai 模块手册api gateway
x/gateway 在边缘提供反向代理、上游健康检查和负载均衡,而不改变上游服务的稳定路由模型。
打开 x/gateway 模块手册real-time
x/websocket 提供全双工 WebSocket 处理,与标准 HTTP 路由共存,复用同一套稳定中间件链和 handler 形态。
打开 x/websocket 模块手册observability
x/observability 提供 exporter、tracer、collector 和 adapter 接线,且不触及稳定路由模型。埋点逻辑留在请求内核之外。
打开 x/observability 模块手册rest api
x/rest 为所有 CRUD 端点提供类型化资源接口、统一响应封装和验证钩子,让每个新资源都遵循同一套结构契约。
打开 x/rest 模块手册messaging
x/messaging 在一个家族入口点下连接消息队列、pubsub 流、定时任务和入站/出站 Webhook 传输,将异步关注点保留在 HTTP 内核之外。
打开 x/messaging 模块手册frontend
x/frontend 将嵌入式或目录式资产服务作为传输层关注点处理。缓存清除、预压缩投递和目录安全均留在扩展层。
打开 x/frontend 模块手册Beta 家族有 API 快照、Owner 确认和晋级证据——可放心用于生产评估。 Experimental 家族已纳入测试,但 API 尚未冻结;从家族入口点开始,预期会有迭代。
API surface 在小版本引用间已冻结,有测试和 Owner 确认,可用于生产评估。
x/rest beta REST 资源 API
使用类型化资源接口、统一响应封装和验证钩子构建 CRUD 资源——无需在每个端点重新发明模式。
x/gateway beta API 网关与代理
在上游服务间路由和重写 HTTP 流量。包括动态服务发现、负载均衡和边缘重写规则。
x/websocket beta 实时 WebSocket
用 Hub 模型管理 WebSocket 连接。广播消息、处理断连,保持传输关注点与业务逻辑分离。
x/observability beta 可观测性与运维工具
附加结构化指标、链路导出器和开发模式诊断工具——不影响稳定请求路径。包含 devtools 和 ops 子包。
x/tenant beta 多租户 SaaS
在传输层解析租户身份并执行每租户策略——不让租户逻辑泄漏到稳定根或 handler 代码。
x/frontend beta 前端资产服务
提供静态资产服务、嵌入 SPA shell、处理缓存清除策略——作为传输层关注点,不污染 handler 或业务逻辑。
x/messaging beta 消息队列与 Webhook
连接消息队列、发布/订阅流、定时任务以及入站或出站 Webhook 传输——统一在一个家族入口点下。下级原语(mq、pubsub、scheduler、webhook)仍为实验性。
已纳入仓库质量门禁并有测试,但 API surface 尚未冻结。从家族入口点开始,勿直接使用子包。
x/ai experimental AI 流式与工具路由
使用 provider contract、session 状态管理和显式工具调用策略构建 AI 流式 SSE 端点——不让 AI 逻辑与 HTTP 内核耦合。稳定层子包(provider、session、streaming、tool)已有 beta 证据。
x/data experimental 数据访问与存储
在 store 稳定根之上添加结构化数据访问原语——类型化查询、迁移和常见持久化场景的 repository 模式。x/data/file 和 x/data/idempotency 已有 beta surface 证据。
x/fileapi experimental 文件上传与下载
处理 multipart 上传、分片下载和临时签名 URL 生成——与 HTTP 内核完全分离。
x/openapi experimental OpenAPI 文档生成
从已注册路由和操作提示生成 OpenAPI 3.1 规范——无依赖的 JSON/YAML 输出,通过 CLI 集成。
x/resilience experimental 弹性与熔断
用重试逻辑、熔断器和超时策略包装上游调用——可组合的原语,保持在稳定传输层之外。
x/rpc experimental gRPC 服务与网关
可选的 gRPC 服务端生命周期助手、出站连接池和 HTTP-over-RPC 网关适配器,与标准 HTTP 路由并行运行。
x/validate experimental 请求验证
在 handler 中显式调用 BindJSON 和 Bind,解码 JSON 并返回结构化的 contract.APIError——不使用 tag 驱动的全局验证器。
架构并不只是包结构故事,它同样是仓库结构故事:docs 负责教路径,reference app 负责证明路径,生成事实负责公开边界,app-local code 负责保持服务 ownership 的可读性,control plane 负责把规则变成机器可读的信号。
docs
Docs 负责先教会 canonical path、request flow 与公开心智模型,而不是让读者单靠包名猜结构。
打开文档reference
reference/standard-service 让默认 bootstrap 与 route ownership 保持可见,让新读者先拥有一条可以对照的仓库基线。
阅读参考应用generated facts
同步生成的事实把稳定根、扩展家族与成熟度信号变成机器可读信号,而不是重复书写的营销表述。
查看项目状态app-local code
internal/app 是服务自有 wiring 最该保持直观的地方。在更深的能力包进入讨论之前,它应该始终是第一站。
查看示例路径control plane
specs/ 以机器可读格式存放 dependency rules、task routing 和 change recipes。AI coding assistant 在改代码之前先读这些规则来分类工作——和人工评审使用的是同一套信号。
阅读 Agent 工作流这两层都重要。差别在于,一层负责保护几乎所有服务都会依赖的默认路径,另一层负责防止可选能力继续向内渗透。
架构页解答改动应该落在哪一层。下一个问题是如何运行它——先从「开始使用」入手,再用「示例」看它实际跑起来的样子。如果仍在评估 Plumego 是否适合,适配判断页是更好的起点。