Marketing / Console / Docs —— 为什么 ByteSpike 用一个仓库发三个应用
ByteSpike 站由三个独立应用挂在三个子域名:bytespike.ai 营销、console.bytespike.ai 客户后台、docs.bytespike.ai Mintlify。三者共享 design token、locale、部署策略 —— 但发布节奏、攻击面、bundle 体积差异够大,强行合并的成本比留这条接缝更贵。
新人进 ByteSpike monorepo 第一个常问的问题是 "为什么三个应用?" 简答:是刻意分开来的。Marketing、Console、Docs 各自服务一类受众、各自有发布节奏、各自风险面不同。强塞一个应用的成本会立刻反映在 bundle 体积、部署速度、以及最痛的事故影响半径上。
三个应用各自是什么
- apps/marketing —— Next.js 15 App Router,静态预渲染,next-intl 双语。bytespike.ai 看到的页面 / pricing / /dosia / /enterprise / /blog / /docs hub。目标:转化访客。客户端交互极少,nav 里有个微小的 auth-status fetch。
- apps/console —— Next.js 15 + server actions + 已登录路由,挂 console.bytespike.ai。钱包、API key、用量、审计日志、成员管理、计费。目标:服务已登录用户。每页都打网关,没法 SSG。
- apps/docs —— Mintlify 独立栈。mint.json + MDX,挂 docs.bytespike.ai。目标:给集成方看的 API reference + concept doc。apps/docs 树里任何东西无需 Next build 直接渲染。
为什么不合并成一个应用
三股力让它们各走各的。一、节奏。Marketing 文案一天发数次;Console 计费逻辑不会、也不该这么做。Marketing typo 卡 Console 计费修复的成本远大于任何 DRY 收益。二、攻击面。Console 处理 JWT cookie + 钱包写入;marketing 不、也不该。把它们塞同一个 Next 进程意味着 marketing 侧任何依赖漏洞都能落到钱包代码路径里。三、bundle 体积。Console 的数据表 / 图表 / 管理 widget 是真实开销。让 /dosia 访客把这些下载下来,会把这个还没赢得客户的页面 LCP 拖崩。
共享什么、不共享什么
通过 workspace package 共享:
- @bytespike/ui —— 品牌 token(CSS 变量)、Logo / Wordmark / Sparkle SVG、bs-card / bs-marquee / bs-gradient-text utility。视觉语言单一信源。
- @bytespike/locales —— 跨接缝的双语文案(货币、日期、计费术语、API 响应标签)。
不共享 —— 刻意:
- Auth —— Console 用 HttpOnly bs_access_token cookie 走网关;marketing 用 document.referrer + localStorage 做 best-effort 暗示。marketing 永远不接触凭据。
- 部署目标 —— marketing + console 是 Next standalone 挂 nginx;docs 是 Mintlify export 跑 Vercel。三个 pipeline、三份 log、三个影响半径。
- i18n 策略 —— marketing 用 next-intl URL 前缀做双语(/zh/...);console 仅已登录、跟随账户偏好;docs 用 Mintlify 每页 locale frontmatter。
“三个应用 = 三份 deploy 日志、三份 bundle 报表、三套回归风险 —— 但任意时刻只有一个会爆炸。”
对贡献者意味着什么
多数 PR 只动一个应用。Token 在 @bytespike/ui —— 改一处品牌色,三个应用下次 build 同步。需要在 pricing 页和 console 计费 tooltip 里逐字相同的文案,归 @bytespike/locales。其他一切 —— 组件、路由、布局 —— 留在它实际发的那个应用里。最朴素的规则我们也守得最好:只被一个应用用到的代码,就只放那一个应用。
如果你以为是一整个 Next monolith,这条接缝看着像 overhead。这套布局跑了 6 个月之后,接缝是便宜那一段。贵的那一段是某天我们其中一个应用依赖的 vendor SDK 中了 CVE —— 那一天,正是这条接缝让补丁成为一个应用的部署而非全站。